[python-escript] 03/04: Bringing git into synch with r5614

Joel Fenwick jfenwick-guest at moszumanska.debian.org
Mon May 18 05:25:32 UTC 2015


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

jfenwick-guest pushed a commit to branch debian
in repository python-escript.

commit 85a86873e4746863d606e761d08ff0d7a825961c
Author: Joel Fenwick <joelfenwick at uq.edu.au>
Date:   Mon May 18 11:59:17 2015 +1000

    Bringing git into synch with r5614
---
 SConstruct                                         |   26 +-
 cusplibrary/SConscript                             |    2 +-
 cusplibrary/cusp/array2d.h                         |    7 +
 cusplibrary/cusp/cds_matrix.h                      |   25 +-
 cusplibrary/cusp/complex.h                         |    7 +
 cusplibrary/cusp/detail/cds_matrix.inl             |   24 +-
 cusplibrary/cusp/detail/copy.inl                   |    7 +
 cusplibrary/cusp/detail/device/conversion.h        |    7 +
 cusplibrary/cusp/detail/device/convert.h           |    7 +
 cusplibrary/cusp/detail/device/multiply.h          |    7 +
 cusplibrary/cusp/detail/device/spmv/cds.h          |   31 +-
 .../cusp/detail/device/spmv/cds_symmetric.h        |   31 +-
 .../cusp/detail/device/transposed_multiply.h       |   31 +-
 .../cusp/detail/device/transposed_spmv/cds.h       |   31 +-
 .../cusp/detail/device/transposed_spmv/dia.h       |   31 +-
 cusplibrary/cusp/detail/dispatch/multiply.h        |    9 +-
 cusplibrary/cusp/detail/format_utils.inl           |    9 +-
 cusplibrary/cusp/detail/host/conversion.h          |    7 +
 cusplibrary/cusp/detail/host/convert.h             |    7 +
 cusplibrary/cusp/detail/host/multiply.h            |    7 +
 cusplibrary/cusp/detail/host/spmv.h                |    7 +
 cusplibrary/cusp/detail/host/transposed_multiply.h |   31 +-
 cusplibrary/cusp/detail/host/transposed_spmv.h     |   31 +-
 cusplibrary/cusp/detail/multiply.inl               |    7 +
 cusplibrary/cusp/dia_matrix.h                      |    7 +
 cusplibrary/cusp/format.h                          |    7 +
 cusplibrary/cusp/gallery/random.h                  |    7 +
 .../cusp/graph/detail/dispatch/hilbert_curve.h     |    9 +-
 cusplibrary/cusp/graph/detail/host/hilbert_curve.h |    7 +
 cusplibrary/cusp/krylov/cgls.h                     |   31 +-
 cusplibrary/cusp/krylov/detail/cgls.inl            |   31 +-
 cusplibrary/cusp/krylov/detail/lsqr.inl            |    8 +
 cusplibrary/cusp/krylov/lsqr.h                     |    7 +
 cusplibrary/cusp/monitor.h                         |    7 +
 cusplibrary/cusp/multiply.h                        |    7 +
 cusplibrary/examples/Algorithms/transposed_spmv.cu |   31 +-
 debian/changelog                                   |    6 +
 debian/changelog.trivial                           |    1 +
 debian/control                                     |   17 +-
 debian/copyright                                   |  230 +-
 debian/patches/series                              |    0
 debian/python-escript-doc.dirs                     |    1 +
 debian/python-escript-doc.examples                 |    1 +
 debian/python-escript-doc.install                  |    7 +
 debian/python-escript-doc.links                    |   19 +
 debian/python-escript-doc.lintian-overrides        |    3 +
 debian/python-escript-mpi.dirs                     |    4 +
 debian/python-escript-mpi.install                  |    5 +
 debian/python-escript-mpi.lintian-overrides        |    6 +
 debian/python-escript-mpi.manpages                 |    1 +
 debian/python-escript-mpi.postinst                 |    4 +-
 debian/python-escript-mpi.prerm                    |    2 +-
 debian/python-escript.dirs                         |    4 +
 debian/python-escript.install                      |    4 +
 debian/python-escript.lintian-overrides            |    7 +
 debian/python-escript.manpages                     |    1 +
 debian/python-escript.postinst                     |    4 +-
 debian/python-escript.prerm                        |    2 +-
 debian/python3-escript-mpi.dirs                    |    4 +
 debian/python3-escript-mpi.install                 |    5 +
 debian/python3-escript-mpi.lintian-overrides       |    5 +
 debian/python3-escript-mpi.manpages                |    1 +
 ...3-mpi.postinst => python3-escript-mpi.postinst} |    4 +-
 ...script3-mpi.prerm => python3-escript-mpi.prerm} |    0
 debian/python3-escript.dirs                        |    4 +
 debian/python3-escript.install                     |    4 +
 debian/python3-escript.lintian-overrides           |    5 +
 debian/python3-escript.manpages                    |    1 +
 ...-escript3.postinst => python3-escript.postinst} |    4 +-
 ...python-escript3.prerm => python3-escript.prerm} |    0
 debian/rules                                       |  279 +-
 debian/source/format                               |    2 +-
 debian/source/lintian-overrides                    |    7 -
 debprep.notes                                      |   36 -
 doc/SConscript                                     |    9 +-
 doc/completedevs.tex                               |    5 +-
 doc/cookbook/SConscript                            |    2 +-
 doc/cookbook/cookbook.bib                          |    2 +-
 doc/cookbook/cookbook.tex                          |    9 +-
 doc/cookbook/cookbook_defs.tex                     |    2 +-
 doc/cookbook/einsteinETA.tex                       |    2 +-
 doc/cookbook/escpybas.tex                          |    2 +-
 doc/cookbook/example01.tex                         |    4 +-
 doc/cookbook/example02.tex                         |    2 +-
 doc/cookbook/example03.tex                         |    2 +-
 doc/cookbook/example04.tex                         |    2 +-
 doc/cookbook/example05.tex                         |    2 +-
 doc/cookbook/example07.tex                         |    2 +-
 doc/cookbook/example08.tex                         |    2 +-
 doc/cookbook/example09.tex                         |    2 +-
 doc/cookbook/example10.tex                         |    2 +-
 doc/cookbook/example11.tex                         |    2 +-
 doc/cookbook/intro.tex                             |    7 +-
 doc/cookbook/quickstart.tex                        |    2 +-
 doc/cookbook/verinfo.tex                           |    7 +
 doc/copyrights.tex                                 |    4 +-
 doc/currentdev.tex                                 |    5 +-
 doc/docguide.tex                                   |    2 +-
 doc/doxygen/SConscript                             |    2 +-
 doc/elist.tex                                      |    2 +-
 doc/epydoc/SConscript                              |    2 +-
 doc/examples/SConscript                            |    4 +-
 doc/examples/cookbook/cblib.py                     |    6 +-
 doc/examples/cookbook/cblib1.py                    |    4 +-
 doc/examples/cookbook/example01a.py                |    4 +-
 doc/examples/cookbook/example01b.py                |    4 +-
 doc/examples/cookbook/example01c.py                |    4 +-
 doc/examples/cookbook/example02.py                 |    4 +-
 doc/examples/cookbook/example03a.py                |    4 +-
 doc/examples/cookbook/example03b.py                |    4 +-
 doc/examples/cookbook/example04a.py                |    4 +-
 doc/examples/cookbook/example04b.py                |   12 +-
 doc/examples/cookbook/example05a.py                |   12 +-
 doc/examples/cookbook/example05b.py                |    4 +-
 doc/examples/cookbook/example05c.py                |    4 +-
 doc/examples/cookbook/example06.py                 |    4 +-
 doc/examples/cookbook/example07a.py                |    4 +-
 doc/examples/cookbook/example07b.py                |    4 +-
 doc/examples/cookbook/example08a.py                |    4 +-
 doc/examples/cookbook/example08b.py                |    4 +-
 doc/examples/cookbook/example08c.py                |    4 +-
 doc/examples/cookbook/example09a.py                |    4 +-
 doc/examples/cookbook/example09b.py                |    4 +-
 doc/examples/cookbook/example09c.py                |    4 +-
 doc/examples/cookbook/example09m.py                |    4 +-
 doc/examples/cookbook/example09n.py                |    4 +-
 doc/examples/cookbook/example10a.py                |    4 +-
 doc/examples/cookbook/example10b.py                |    4 +-
 doc/examples/cookbook/example10c_0.py              |    4 +-
 doc/examples/cookbook/example10c_1.py              |    4 +-
 doc/examples/cookbook/example10d.py                |    4 +-
 doc/examples/cookbook/example10e.py                |    4 +-
 doc/examples/cookbook/example10m.py                |    4 +-
 doc/examples/cookbook/example10p.py                |    4 +-
 doc/examples/cookbook/example11a.py                |    4 +-
 doc/examples/cookbook/example11b.py                |    4 +-
 doc/examples/cookbook/example11c.py                |    4 +-
 doc/examples/cookbook/example11m.py                |    4 +-
 doc/examples/cookbook/wave_stab.py                 |    4 +-
 doc/examples/cookbook/wavesolver2d001.py           |    4 +-
 doc/examples/cookbook/wavesolver2d002.py           |    4 +-
 doc/examples/cookbook/wavesolver2d003.py           |    4 +-
 doc/examples/cookbook/wavesolver2d004.py           |    4 +-
 doc/examples/geotutorial/backward_euler.py         |    4 +-
 doc/examples/geotutorial/forward_euler.py          |    4 +-
 doc/examples/geotutorial/myfirstscript.py          |    4 +-
 doc/examples/geotutorial/steadystate.py            |    4 +-
 doc/examples/geotutorial/steadystate_variablek.py  |    4 +-
 doc/examples/inversion/create_netcdf.py            |    2 +-
 doc/examples/inversion/dc_forward.py               |   10 +-
 doc/examples/inversion/grav_ermapper.py            |    4 +-
 doc/examples/inversion/grav_netcdf.py              |    4 +-
 doc/examples/inversion/gravmag_netcdf.py           |    4 +-
 doc/examples/inversion/gravmag_nodriver.py         |    4 +-
 doc/examples/inversion/gravmag_wgs84_nodriver.py   |    4 +-
 doc/examples/inversion/mag_netcdf.py               |    4 +-
 doc/examples/inversion/mag_wgs84_netcdf.py         |    4 +-
 doc/examples/inversion/plot_ermapper.py            |    2 +-
 doc/examples/inversion/plot_netcdf.py              |    2 +-
 doc/examples/inversion/strong_gravmag_netcdf.py    |    4 +-
 doc/examples/inversion/synthetic_HTI.py            |    4 +-
 doc/examples/inversion/synthetic_TTI.py            |    4 +-
 doc/examples/inversion/synthetic_VTI.py            |    4 +-
 doc/examples/inversion/synthetic_sonic.py          |    4 +-
 doc/examples/inversion/synthetic_sonicHTI.py       |    4 +-
 doc/examples/usersguide/brick.py                   |    4 +-
 doc/examples/usersguide/brick_stl.py               |    4 +-
 doc/examples/usersguide/darcy.py                   |    4 +-
 doc/examples/usersguide/diffusion.py               |    4 +-
 doc/examples/usersguide/fluid.py                   |    2 +-
 doc/examples/usersguide/heatedblock.py             |    4 +-
 doc/examples/usersguide/helmholtz.py               |    4 +-
 doc/examples/usersguide/int_save.py                |    4 +-
 doc/examples/usersguide/lid_driven_cavity.py       |    4 +-
 doc/examples/usersguide/mount.py                   |    4 +-
 doc/examples/usersguide/poisson.py                 |    4 +-
 doc/examples/usersguide/poisson_matplotlib.py      |    4 +-
 doc/examples/usersguide/poisson_vtk.py             |    4 +-
 doc/examples/usersguide/quad.py                    |    4 +-
 doc/examples/usersguide/refine.py                  |    4 +-
 doc/examples/usersguide/slip.py                    |    4 +-
 doc/examples/usersguide/trapezoid.py               |    4 +-
 doc/examples/usersguide/wave.py                    |    4 +-
 doc/install/SConscript                             |    2 +-
 doc/install/allsrccommon.tex                       |    2 +-
 doc/install/binary.tex                             |   80 -
 doc/install/bincommon.tex                          |   31 -
 doc/install/binlinux.tex                           |    2 +-
 doc/install/binmac.tex                             |    2 +-
 doc/install/binwin.tex                             |   49 -
 doc/install/chcomp.tex                             |    2 +-
 doc/install/compiler.tex                           |    2 +-
 doc/install/debbin.tex                             |   26 +-
 doc/install/install.tex                            |    8 +-
 doc/install/install_defs.tex                       |    5 +-
 doc/install/intro.tex                              |    4 +-
 doc/install/source.tex                             |   25 +-
 doc/install/srcadditional.tex                      |    2 +-
 doc/install/srclinux.tex                           |    2 +-
 doc/install/srcmac.tex                             |    2 +-
 doc/install/srcommon.tex                           |  265 -
 doc/install/verinfo.tex                            |    7 +
 doc/install/winstall.tex                           |   48 -
 doc/inversion/CookDcRes.tex                        |    2 +-
 doc/inversion/Forward2DMTTEMode.tex                |    2 +-
 doc/inversion/ForwardDCRES.tex                     |    2 +-
 doc/inversion/ForwardGravity.tex                   |    2 +-
 doc/inversion/ForwardMagnetic.tex                  |    2 +-
 doc/inversion/ForwardSelfMagnetic.tex              |    2 +-
 doc/inversion/Minimization.tex                     |    2 +-
 doc/inversion/SConscript                           |    2 +-
 doc/inversion/defs.tex                             |    2 +-
 doc/inversion/intro.tex                            |    2 +-
 doc/inversion/inversion.tex                        |    8 +-
 doc/inversion/verinfo.tex                          |    7 +
 doc/sphinx_api/SConscript                          |    2 +-
 doc/sphinx_api/genrst.py                           |    8 +-
 doc/user/Models.tex                                |    2 +-
 doc/user/SConscript                                |    2 +-
 doc/user/TutorialPDE.tex                           |    2 +-
 doc/user/appendix.tex                              |    2 +-
 doc/user/changes.tex                               |    2 +-
 doc/user/darcyflux.tex                             |    2 +-
 doc/user/diffusion.tex                             |    2 +-
 doc/user/escript.tex                               |    2 +-
 doc/user/execute.tex                               |    2 +-
 doc/user/faultsystem.tex                           |    2 +-
 doc/user/finley.tex                                |    2 +-
 doc/user/finleyelements.tex                        |    2 +-
 doc/user/firststep.tex                             |    2 +-
 doc/user/heatedblock.tex                           |    2 +-
 doc/user/levelset.tex                              |    2 +-
 doc/user/levelsetmodel.tex                         |    2 +-
 doc/user/linearPDE.tex                             |    2 +-
 doc/user/lumping.tex                               |    2 +-
 doc/user/modelframe.tex                            |    2 +-
 doc/user/nonlinearPDE.tex                          |    2 +-
 doc/user/notation.tex                              |    2 +-
 doc/user/ourrefs.tex                               |    2 +-
 doc/user/py3.tex                                   |    2 +-
 doc/user/pycad.tex                                 |    2 +-
 doc/user/ripley.tex                                |    2 +-
 doc/user/slip.tex                                  |    2 +-
 doc/user/speckley.tex                              |    2 +-
 doc/user/stokesflow.tex                            |    2 +-
 doc/user/stokessolver.tex                          |    2 +-
 doc/user/symbolic.tex                              |    2 +-
 doc/user/user.tex                                  |    7 +-
 doc/user/user_defs.tex                             |    2 +-
 doc/user/verinfo.tex                               |    7 +
 doc/user/wave.tex                                  |    2 +-
 doc/user/weipa.tex                                 |    2 +-
 doc/verinfo.tex                                    |    7 +
 downunder/py_src/SConscript                        |    7 +-
 downunder/py_src/__init__.py                       |    6 +-
 downunder/py_src/coordinates.py                    |    4 +-
 downunder/py_src/costfunctions.py                  |    4 +-
 downunder/py_src/datasources.py                    |    4 +-
 downunder/py_src/dcresistivityforwardmodeling.py   |  157 +-
 downunder/py_src/domainbuilder.py                  |    4 +-
 downunder/py_src/domaingeneratordcresistivity.py   |  147 +-
 downunder/py_src/forwardmodels.py                  | 1571 ----
 .../py_src/forwardmodels}/__init__.py              |   19 +-
 downunder/py_src/forwardmodels/acoustic.py         |  319 +
 downunder/py_src/forwardmodels/base.py             |  206 +
 downunder/py_src/forwardmodels/dcresistivity.py    |  260 +
 downunder/py_src/forwardmodels/gravity.py          |  151 +
 downunder/py_src/forwardmodels/magnetic.py         |  302 +
 .../py_src/forwardmodels/magnetotelluric2d.py      |  554 ++
 downunder/py_src/forwardmodels/pressure.py         |  102 +
 downunder/py_src/forwardmodels/subsidence.py       |  135 +
 downunder/py_src/inversioncostfunctions.py         |   13 +-
 downunder/py_src/inversions.py                     |    4 +-
 downunder/py_src/mappings.py                       |   39 +-
 downunder/py_src/minimizers.py                     |    4 +-
 downunder/py_src/regularizations.py                |    6 +-
 downunder/py_src/seismic.py                        |   67 +-
 ...functions.py => splitinversioncostfunctions.py} |  393 +-
 downunder/py_src/splitminimizers.py                |  231 +
 ...{regularizations.py => splitregularizations.py} |   29 +-
 downunder/test/python/SConscript                   |    2 +-
 downunder/test/python/inversion_acoustictest_2d.py |    4 +-
 downunder/test/python/run_coordinates.py           |    4 +-
 downunder/test/python/run_datasources.py           |   14 +-
 downunder/test/python/run_dcforward.py             |  172 +-
 downunder/test/python/run_domainbuilder.py         |    4 +-
 downunder/test/python/run_forward.py               |  586 +-
 downunder/test/python/run_gravity.py               |    4 +-
 downunder/test/python/run_inversion_gravmag_2d.py  |    4 +-
 downunder/test/python/run_inversioncostfunction.py |    4 +-
 downunder/test/python/run_magnetic.py              |    4 +-
 downunder/test/python/run_mappings.py              |    4 +-
 downunder/test/python/run_minimizers.py            |    4 +-
 downunder/test/python/run_regularization.py        |    4 +-
 downunder/test/python/run_seismic.py               |    4 +-
 dudley/benchmarks/dudleybench.py                   |    4 +-
 dudley/benchmarks/runbenchmark.py                  |    4 +-
 dudley/py_src/SConscript                           |    2 +-
 dudley/py_src/__init__.py                          |    4 +-
 dudley/py_src/factorywrappers.py                   |    8 +-
 dudley/py_src/readers.py                           |    4 +-
 dudley/src/Assemble.h                              |   76 +-
 dudley/src/Assemble_AverageElementData.cpp         |    7 +-
 dudley/src/Assemble_CopyElementData.cpp            |    7 +-
 dudley/src/Assemble_CopyNodalData.cpp              |   24 +-
 dudley/src/Assemble_LumpedSystem.cpp               |   21 +-
 dudley/src/Assemble_NodeCoordinates.cpp            |    7 +-
 dudley/src/Assemble_PDE.cpp                        |   11 +-
 dudley/src/Assemble_PDE_Points.cpp                 |    8 +-
 dudley/src/Assemble_PDE_Single2_1D.cpp             |    2 +-
 dudley/src/Assemble_PDE_Single2_2D.cpp             |   11 +-
 dudley/src/Assemble_PDE_Single2_3D.cpp             |   11 +-
 dudley/src/Assemble_PDE_System2_1D.cpp             |    2 +-
 dudley/src/Assemble_PDE_System2_2D.cpp             |   11 +-
 dudley/src/Assemble_PDE_System2_3D.cpp             |   11 +-
 dudley/src/Assemble_addToSystemMatrix.cpp          |    5 +-
 dudley/src/Assemble_getAssembleParameters.cpp      |    7 +-
 dudley/src/Assemble_getSize.cpp                    |    7 +-
 dudley/src/Assemble_gradient.cpp                   |    8 +-
 dudley/src/Assemble_integrate.cpp                  |    7 +-
 dudley/src/Assemble_interpolate.cpp                |    9 +-
 dudley/src/Assemble_jacobeans.cpp                  |    5 +-
 dudley/src/Assemble_setNormal.cpp                  |    7 +-
 dudley/src/CPPAdapter/DudleyAdapterException.cpp   |    2 +-
 dudley/src/CPPAdapter/DudleyAdapterException.h     |    2 +-
 dudley/src/CPPAdapter/DudleyError.cpp              |    2 +-
 dudley/src/CPPAdapter/DudleyError.h                |    2 +-
 dudley/src/CPPAdapter/MeshAdapter.cpp              |  220 +-
 dudley/src/CPPAdapter/MeshAdapter.h                |    8 +-
 dudley/src/CPPAdapter/MeshAdapterFactory.cpp       |    6 +-
 dudley/src/CPPAdapter/MeshAdapterFactory.h         |    2 +-
 dudley/src/CPPAdapter/dudleycpp.cpp                |    5 +-
 dudley/src/CPPAdapter/system_dep.h                 |   17 +-
 dudley/src/Dudley.cpp                              |    2 +-
 dudley/src/Dudley.h                                |    2 +-
 dudley/src/DudleyVersion.h                         |    4 +-
 dudley/src/ElementFile.cpp                         |    5 +-
 dudley/src/ElementFile.h                           |    4 +-
 dudley/src/ElementFile_allocTable.cpp              |    5 +-
 dudley/src/ElementFile_copyTable.cpp               |    4 +-
 dudley/src/ElementFile_createColoring.cpp          |    5 +-
 dudley/src/ElementFile_distributeByRankOfDOF.cpp   |    6 +-
 dudley/src/ElementFile_gather.cpp                  |    5 +-
 dudley/src/ElementFile_jacobeans.cpp               |    5 +-
 dudley/src/ElementFile_markNodes.cpp               |    5 +-
 dudley/src/ElementFile_optimizeOrdering.cpp        |    5 +-
 dudley/src/ElementFile_relableNodes.cpp            |    5 +-
 dudley/src/ElementFile_scatter.cpp                 |    5 +-
 dudley/src/ElementFile_setCoordinates.cpp          |   10 +-
 dudley/src/ElementFile_setNodeRange.cpp            |    5 +-
 dudley/src/ElementFile_setTags.cpp                 |    7 +-
 dudley/src/ElementType.cpp                         |    2 +-
 dudley/src/ElementType.h                           |    2 +-
 dudley/src/IndexList.cpp                           |    5 +-
 dudley/src/IndexList.h                             |    2 +-
 dudley/src/Mesh.cpp                                |    5 +-
 dudley/src/Mesh.h                                  |    4 +-
 dudley/src/Mesh_createNodeFileMappings.cpp         |    5 +-
 dudley/src/Mesh_distributeByRankOfDOF.cpp          |    5 +-
 dudley/src/Mesh_findMatchingFaces.cpp              |    5 +-
 dudley/src/Mesh_getPattern.cpp                     |    5 +-
 dudley/src/Mesh_markNodes.cpp                      |    5 +-
 dudley/src/Mesh_optimizeDOFDistribution.cpp        |  382 +-
 dudley/src/Mesh_optimizeDOFLabeling.cpp            |    5 +-
 dudley/src/Mesh_prepare.cpp                        |    5 +-
 dudley/src/Mesh_print.cpp                          |    5 +-
 dudley/src/Mesh_read.cpp                           |    5 +-
 dudley/src/Mesh_readGmsh.cpp                       |    5 +-
 dudley/src/Mesh_relableElementNodes.cpp            |    5 +-
 dudley/src/Mesh_resolveNodeIds.cpp                 |    5 +-
 dudley/src/Mesh_setCoordinates.cpp                 |   10 +-
 dudley/src/Mesh_tagmaps.cpp                        |    5 +-
 dudley/src/Mesh_tet4.cpp                           |    5 +-
 dudley/src/Mesh_tri3.cpp                           |    5 +-
 dudley/src/Mesh_write.cpp                          |    5 +-
 dudley/src/NodeFile.cpp                            |    5 +-
 dudley/src/NodeFile.h                              |    6 +-
 dudley/src/NodeFile_allocTable.cpp                 |    5 +-
 dudley/src/NodeFile_copyTable.cpp                  |    5 +-
 dudley/src/NodeFile_createDenseLabelings.cpp       |    5 +-
 dudley/src/NodeFile_gather.cpp                     |    5 +-
 dudley/src/NodeFile_scatter.cpp                    |    5 +-
 dudley/src/NodeFile_setCoordinates.cpp             |    7 +-
 dudley/src/NodeFile_setIdRange.cpp                 |    5 +-
 dudley/src/NodeFile_setTags.cpp                    |    7 +-
 dudley/src/NodeMapping.cpp                         |    2 +-
 dudley/src/NodeMapping.h                           |    2 +-
 dudley/src/SConscript                              |    2 +-
 dudley/src/ShapeTable.cpp                          |    2 +-
 dudley/src/ShapeTable.h                            |    2 +-
 dudley/src/TagMap.cpp                              |    2 +-
 dudley/src/TagMap.h                                |    2 +-
 dudley/src/TriangularMesh.h                        |    2 +-
 dudley/src/Util.cpp                                |    2 +-
 dudley/src/Util.h                                  |    2 +-
 dudley/src/generateReferenceElementList.py         |    2 +-
 dudley/test/MeshAdapterTestCase.cpp                |    5 +-
 dudley/test/MeshAdapterTestCase.h                  |    2 +-
 dudley/test/SConscript                             |    2 +-
 dudley/test/dudley_UnitTests.cpp                   |    2 +-
 dudley/test/python/FCT_benchmark.py                |    4 +-
 dudley/test/python/FCT_test1.py                    |    4 +-
 dudley/test/python/FCT_test2.py                    |    4 +-
 dudley/test/python/OutTest.py                      |    4 +-
 dudley/test/python/PoissonSolverTest.py            |    4 +-
 dudley/test/python/RecTest.py                      |    4 +-
 dudley/test/python/SConscript                      |    4 +-
 dudley/test/python/axisymm-splitB.py               |    4 +-
 dudley/test/python/blocktest.py                    |    4 +-
 dudley/test/python/brick.py                        |    4 +-
 dudley/test/python/convection.py                   |    4 +-
 dudley/test/python/fixme_run_generators.py         |    4 +-
 dudley/test/python/generate_dumps.py               |    4 +-
 dudley/test/python/generate_meshes.py              |    4 +-
 dudley/test/python/linearElastic.py                |    4 +-
 dudley/test/python/rayleigh_taylor_instabilty.py   |    4 +-
 dudley/test/python/rectangle.py                    |    4 +-
 dudley/test/python/run_escriptOnDudley.py          |    5 +-
 dudley/test/python/run_inputOutput.py              |    4 +-
 dudley/test/python/run_linearPDEsOnDudley1.py      |    4 +-
 dudley/test/python/run_linearPDEsOnDudley2.py      |    4 +-
 dudley/test/python/run_models.py                   |    4 +-
 dudley/test/python/run_nlpde2dOnDudley.py          |    4 +-
 dudley/test/python/run_nlpde3dOnDudley.py          |    4 +-
 dudley/test/python/run_simplesolve.py              |    4 +-
 dudley/test/python/run_utilOnDudley.py             |   11 +-
 dudley/test/python/seismic_wave.py                 |    4 +-
 dudley/test/python/slip_stress_mesh_old.py         |    4 +-
 dudley/test/python/slip_stress_old.py              |    4 +-
 dudley/test/python/stokes_problems.py              |    4 +-
 dudley/test/python/subduction1.py                  |    4 +-
 dudley/test/python/subduction1_gen.py              |    4 +-
 dudley/test/python/time_chunks.py                  |    4 +-
 dudley/test/python/tp.py                           |    4 +-
 escript/py_src/SConscript                          |    2 +-
 escript/py_src/__init__.py                         |    5 +-
 escriptcore/py_src/SConscript                      |    2 +-
 escriptcore/py_src/__init__.py                     |    4 +-
 escriptcore/py_src/benchmark.py                    |    4 +-
 escriptcore/py_src/datamanager.py                  |    4 +-
 escriptcore/py_src/domainCouplers.py               |    6 +-
 escriptcore/py_src/faultsystems.py                 |    4 +-
 escriptcore/py_src/flows.py                        |    4 +-
 escriptcore/py_src/gmshrunner.py                   |   20 +-
 escriptcore/py_src/heat.py                         |    4 +-
 escriptcore/py_src/levelset.py                     |    4 +-
 escriptcore/py_src/linearPDEs.py                   |    7 +-
 escriptcore/py_src/modelframe.py                   |    4 +-
 escriptcore/py_src/models.py                       |    4 +-
 escriptcore/py_src/mountains.py                    |    4 +-
 escriptcore/py_src/nonlinearPDE.py                 |    4 +-
 escriptcore/py_src/pdetools.py                     |    4 +-
 escriptcore/py_src/rheologies.py                   |    4 +-
 escriptcore/py_src/runmodel.py                     |    4 +-
 escriptcore/py_src/splitworld.py                   |   41 +-
 escriptcore/py_src/start.py                        |    4 +-
 escriptcore/py_src/symbolic/__init__.py            |    4 +-
 escriptcore/py_src/symbolic/evaluator.py           |    6 +-
 escriptcore/py_src/symbolic/functions.py           |    4 +-
 escriptcore/py_src/symbolic/pretty.py              |    4 +-
 escriptcore/py_src/symbolic/symbol.py              |    4 +-
 escriptcore/py_src/symbolic/utils.py               |    4 +-
 escriptcore/py_src/testing.py                      |   29 +-
 escriptcore/py_src/unitsSI.py                      |    4 +-
 escriptcore/py_src/utestselect.py                  |    4 +-
 escriptcore/py_src/util.py                         |    4 +-
 escriptcore/src/AbstractContinuousDomain.cpp       |    5 +-
 escriptcore/src/AbstractContinuousDomain.h         |    2 +-
 escriptcore/src/AbstractDomain.cpp                 |    6 +-
 escriptcore/src/AbstractDomain.h                   |   12 +-
 ...SplitWorldException.cpp => AbstractReducer.cpp} |   32 +-
 escriptcore/src/{Reducer.h => AbstractReducer.h}   |   79 +-
 escriptcore/src/AbstractSystemMatrix.cpp           |    5 +-
 escriptcore/src/AbstractSystemMatrix.h             |    2 +-
 escriptcore/src/AbstractTransportProblem.cpp       |    5 +-
 escriptcore/src/AbstractTransportProblem.h         |    2 +-
 escriptcore/src/BinaryOp.h                         |    2 +-
 escriptcore/src/Data.cpp                           |   24 +-
 escriptcore/src/Data.h                             |   24 +-
 escriptcore/src/DataAbstract.cpp                   |    5 +-
 escriptcore/src/DataAbstract.h                     |    2 +-
 escriptcore/src/DataAlgorithm.h                    |    2 +-
 escriptcore/src/DataBlocks2D.cpp                   |    2 +-
 escriptcore/src/DataBlocks2D.h                     |    2 +-
 escriptcore/src/DataC.cpp                          |  118 +-
 escriptcore/src/DataC.h                            |   54 +-
 escriptcore/src/DataConstant.cpp                   |    4 +-
 escriptcore/src/DataConstant.h                     |    2 +-
 escriptcore/src/DataEmpty.cpp                      |    4 +-
 escriptcore/src/DataEmpty.h                        |    2 +-
 escriptcore/src/DataException.cpp                  |    2 +-
 escriptcore/src/DataException.h                    |    2 +-
 escriptcore/src/DataExpanded.cpp                   |    4 +-
 escriptcore/src/DataExpanded.h                     |    2 +-
 escriptcore/src/DataFactory.cpp                    |    5 +-
 escriptcore/src/DataFactory.h                      |   13 +-
 escriptcore/src/DataLazy.cpp                       |    4 +-
 escriptcore/src/DataLazy.h                         |    2 +-
 escriptcore/src/DataMaths.cpp                      |    4 +-
 escriptcore/src/DataMaths.h                        |    2 +-
 escriptcore/src/DataReady.cpp                      |    6 +-
 escriptcore/src/DataReady.h                        |    2 +-
 escriptcore/src/DataTagged.cpp                     |    5 +-
 escriptcore/src/DataTagged.h                       |    2 +-
 escriptcore/src/DataTypes.cpp                      |    5 +-
 escriptcore/src/DataTypes.h                        |    2 +-
 escriptcore/src/DataVector.cpp                     |    5 +-
 escriptcore/src/DataVector.h                       |    2 +-
 escriptcore/src/Dodgy.cpp                          |    2 +-
 escriptcore/src/Dodgy.h                            |    2 +-
 escriptcore/src/DomainException.cpp                |    2 +-
 escriptcore/src/DomainException.h                  |    2 +-
 escriptcore/src/EscriptParams.cpp                  |    6 +-
 escriptcore/src/EscriptParams.h                    |    2 +-
 escriptcore/src/FunctionSpace.cpp                  |    5 +-
 escriptcore/src/FunctionSpace.h                    |    2 +-
 escriptcore/src/FunctionSpaceException.cpp         |    2 +-
 escriptcore/src/FunctionSpaceException.h           |    2 +-
 escriptcore/src/FunctionSpaceFactory.cpp           |    5 +-
 escriptcore/src/FunctionSpaceFactory.h             |    2 +-
 escriptcore/src/LapackInverseHelper.cpp            |    2 +-
 escriptcore/src/LapackInverseHelper.h              |    2 +-
 escriptcore/src/LocalOps.h                         |    8 +-
 .../src/{Reducer.cpp => MPIDataReducer.cpp}        |   50 +-
 escriptcore/src/MPIDataReducer.h                   |   77 +
 escriptcore/src/MPIScalarReducer.cpp               |  271 +
 escriptcore/src/MPIScalarReducer.h                 |   80 +
 escriptcore/src/NonReducedVariable.cpp             |  121 +
 escriptcore/src/NonReducedVariable.h               |   80 +
 escriptcore/src/NullDomain.cpp                     |    9 +-
 escriptcore/src/NullDomain.h                       |    2 +-
 escriptcore/src/Pointers.h                         |    2 +-
 escriptcore/src/SConscript                         |   12 +-
 escriptcore/src/SolverOptions.cpp                  |    2 +-
 escriptcore/src/SolverOptions.h                    |   13 +-
 escriptcore/src/SolverOptionsException.cpp         |    2 +-
 escriptcore/src/SolverOptionsException.h           |    2 +-
 escriptcore/src/SplitWorld.cpp                     |  363 +-
 escriptcore/src/SplitWorld.h                       |   29 +-
 escriptcore/src/SplitWorldException.cpp            |    2 +-
 escriptcore/src/SplitWorldException.h              |    2 +-
 escriptcore/src/SubWorld.cpp                       |  837 +-
 escriptcore/src/SubWorld.h                         |   97 +-
 escriptcore/src/SystemMatrixException.cpp          |    2 +-
 escriptcore/src/SystemMatrixException.h            |    2 +-
 escriptcore/src/Taipan.cpp                         |    2 +-
 escriptcore/src/Taipan.h                           |    2 +-
 escriptcore/src/TestDomain.cpp                     |    5 +-
 escriptcore/src/TestDomain.h                       |    2 +-
 escriptcore/src/TransportProblemException.cpp      |    2 +-
 escriptcore/src/TransportProblemException.h        |    2 +-
 escriptcore/src/UnaryFuncs.h                       |    2 +-
 escriptcore/src/UnaryOp.h                          |    2 +-
 escriptcore/src/UtilC.h                            |    2 +-
 escriptcore/src/Utils.cpp                          |  197 +-
 escriptcore/src/Utils.h                            |    2 +-
 escriptcore/src/WrappedArray.cpp                   |    2 +-
 escriptcore/src/WrappedArray.h                     |    2 +-
 escriptcore/src/escriptcpp.cpp                     |   32 +-
 escriptcore/src/system_dep.h                       |   21 +-
 escriptcore/test/DataAlgorithmAdapterTestCase.cpp  |   10 +-
 escriptcore/test/DataAlgorithmAdapterTestCase.h    |    2 +-
 escriptcore/test/DataBlocks2DTestCase.cpp          |    5 +-
 escriptcore/test/DataBlocks2DTestCase.h            |    2 +-
 escriptcore/test/DataConstantTestCase.cpp          |    5 +-
 escriptcore/test/DataConstantTestCase.h            |    2 +-
 escriptcore/test/DataEmptyTestCase.cpp             |    6 +-
 escriptcore/test/DataEmptyTestCase.h               |    2 +-
 escriptcore/test/DataExpandedTestCase.cpp          |   14 +-
 escriptcore/test/DataExpandedTestCase.h            |    2 +-
 escriptcore/test/DataFactoryTestCase.cpp           |   15 +-
 escriptcore/test/DataFactoryTestCase.h             |    2 +-
 escriptcore/test/DataLazyTestCase.cpp              |    5 +-
 escriptcore/test/DataLazyTestCase.h                |    2 +-
 escriptcore/test/DataMathsTestCase.cpp             |    5 +-
 escriptcore/test/DataMathsTestCase.h               |    2 +-
 escriptcore/test/DataTaggedTestCase.cpp            |    5 +-
 escriptcore/test/DataTaggedTestCase.h              |    2 +-
 escriptcore/test/DataTestCase.cpp                  |   10 +-
 escriptcore/test/DataTestCase.h                    |    2 +-
 escriptcore/test/DataTypesTestCase.cpp             |    5 +-
 escriptcore/test/DataTypesTestCase.h               |    2 +-
 escriptcore/test/DataVectorTestCase.cpp            |    5 +-
 escriptcore/test/DataVectorTestCase.h              |    2 +-
 escriptcore/test/FunctionSpaceTestCase.cpp         |    6 +-
 escriptcore/test/FunctionSpaceTestCase.h           |    2 +-
 escriptcore/test/SConscript                        |    2 +-
 escriptcore/test/SharedDataTestCase.cpp            |    6 +-
 escriptcore/test/SharedDataTestCase.h              |    2 +-
 escriptcore/test/TaipanTestCase.cpp                |    5 +-
 escriptcore/test/TaipanTestCase.h                  |    2 +-
 escriptcore/test/escript_UnitTest.cpp              |    2 +-
 escriptcore/test/multi_arrayTestCase.cpp           |    5 +-
 escriptcore/test/multi_arrayTestCase.h             |    2 +-
 escriptcore/test/python/SConscript                 |    6 +-
 escriptcore/test/python/TimingTests.py.old         |    4 +-
 escriptcore/test/python/run_data_access.py         |    4 +-
 escriptcore/test/python/run_symbolic.py            |    4 +-
 escriptcore/test/python/run_testdomain.py          |    4 +-
 escriptcore/test/python/run_units.py               |    4 +-
 escriptcore/test/python/run_xml.py                 |    4 +-
 escriptcore/test/python/test_assemblage.py         |    4 +-
 escriptcore/test/python/test_assemblage_2Do1.py    |    4 +-
 escriptcore/test/python/test_assemblage_2Do2.py    |    4 +-
 escriptcore/test/python/test_assemblage_3Do1.py    |    4 +-
 escriptcore/test/python/test_assemblage_3Do2.py    |    4 +-
 escriptcore/test/python/test_condEval.py           |    4 +-
 escriptcore/test/python/test_linearPDEs.py         |    4 +-
 escriptcore/test/python/test_modulefns.py          |    4 +-
 escriptcore/test/python/test_nonLinearPDE.py       |    4 +-
 escriptcore/test/python/test_objects.py            |   10 +-
 escriptcore/test/python/test_pdetools.py           |    4 +-
 escriptcore/test/python/test_shared.py             |    4 +-
 escriptcore/test/python/test_splitworld.py         |  478 +
 escriptcore/test/python/test_symfuncs.py           |    4 +-
 escriptcore/test/python/test_util.py               |    4 +-
 escriptcore/test/python/test_util_base.py          |   15 +-
 .../test/python/test_util_binary_no_tagged_data.py |    4 +-
 .../python/test_util_binary_with_tagged_data.py    |    4 +-
 .../test_util_overloaded_binary_no_tagged_data.py  |    4 +-
 ...test_util_overloaded_binary_with_tagged_data.py |    4 +-
 .../python/test_util_reduction_no_tagged_data.py   |    4 +-
 .../python/test_util_reduction_with_tagged_data.py |    4 +-
 .../python/test_util_slicing_no_tagged_data.py     |    4 +-
 .../python/test_util_slicing_with_tagged_data.py   |    4 +-
 .../test/python/test_util_spatial_functions1.py    |    4 +-
 .../test/python/test_util_spatial_functions2.py    |    4 +-
 .../test/python/test_util_spatial_functions3.py    |    4 +-
 .../test/python/test_util_unary_no_tagged_data.py  |    4 +-
 .../python/test_util_unary_with_tagged_data.py     |    4 +-
 esysUtils/src/EsysAssert.h                         |    2 +-
 esysUtils/src/EsysAssertException.cpp              |    2 +-
 esysUtils/src/EsysAssertException.h                |    2 +-
 esysUtils/src/EsysException.cpp                    |    2 +-
 esysUtils/src/EsysException.h                      |    2 +-
 esysUtils/src/EsysRandom.cpp                       |    2 +-
 esysUtils/src/EsysRandom.h                         |    2 +-
 esysUtils/src/Esys_MPI.cpp                         |  155 +-
 esysUtils/src/Esys_MPI.h                           |   12 +-
 esysUtils/src/IndexList.h                          |    2 +-
 esysUtils/src/SConscript                           |    5 +-
 esysUtils/src/blocktimer.cpp                       |    2 +-
 esysUtils/src/blocktimer.h                         |    2 +-
 esysUtils/src/error.cpp                            |    2 +-
 esysUtils/src/error.h                              |    2 +-
 esysUtils/src/esysExceptionTranslator.cpp          |    5 +-
 esysUtils/src/esysExceptionTranslator.h            |    2 +-
 esysUtils/src/esysFileWriter.h                     |    2 +-
 escriptcore/src/UtilC.h => esysUtils/src/first.h   |   13 +-
 esysUtils/src/index.h                              |    2 +-
 esysUtils/src/maths.h                              |   32 +-
 esysUtils/src/mem.h                                |    2 +-
 esysUtils/src/pyerr.cpp                            |   45 +
 escriptcore/src/UtilC.h => esysUtils/src/pyerr.h   |   17 +-
 esysUtils/src/system_dep.h                         |   22 +-
 esysUtils/src/types.h                              |    2 +-
 esysUtils/test/EsysExceptionTestCase.cpp           |    2 +-
 esysUtils/test/EsysExceptionTestCase.h             |    2 +-
 esysUtils/test/EsysFileWriterTestCase.cpp          |    2 +-
 esysUtils/test/EsysFileWriterTestCase.h            |    2 +-
 esysUtils/test/SConscript                          |    2 +-
 esysUtils/test/esysUtils_UnitTest.cpp              |    2 +-
 finley/benchmarks/finleybench.py                   |    4 +-
 finley/benchmarks/runbenchmark.py                  |    4 +-
 finley/py_src/SConscript                           |    2 +-
 finley/py_src/__init__.py                          |    4 +-
 finley/py_src/factorywrappers.py                   |   12 +-
 finley/py_src/readers.py                           |    4 +-
 finley/src/Assemble.h                              |    2 +-
 finley/src/Assemble_AverageElementData.cpp         |    6 +-
 finley/src/Assemble_CopyElementData.cpp            |    6 +-
 finley/src/Assemble_CopyNodalData.cpp              |    6 +-
 finley/src/Assemble_LumpedSystem.cpp               |    6 +-
 finley/src/Assemble_NodeCoordinates.cpp            |    6 +-
 finley/src/Assemble_PDE.cpp                        |    6 +-
 finley/src/Assemble_PDE_Points.cpp                 |    5 +-
 finley/src/Assemble_PDE_Single_1D.cpp              |    5 +-
 finley/src/Assemble_PDE_Single_2D.cpp              |   14 +-
 finley/src/Assemble_PDE_Single_3D.cpp              |   14 +-
 finley/src/Assemble_PDE_Single_C.cpp               |    7 +-
 finley/src/Assemble_PDE_System_1D.cpp              |    6 +-
 finley/src/Assemble_PDE_System_2D.cpp              |   14 +-
 finley/src/Assemble_PDE_System_3D.cpp              |   14 +-
 finley/src/Assemble_PDE_System_C.cpp               |    8 +-
 finley/src/Assemble_addToSystemMatrix.cpp          |    6 +-
 finley/src/Assemble_getAssembleParameters.cpp      |    5 +-
 finley/src/Assemble_getNormal.cpp                  |    5 +-
 finley/src/Assemble_getSize.cpp                    |    4 +-
 finley/src/Assemble_gradient.cpp                   |    5 +-
 finley/src/Assemble_integrate.cpp                  |    6 +-
 finley/src/Assemble_interpolate.cpp                |    6 +-
 finley/src/Assemble_jacobians.cpp                  |    6 +-
 finley/src/CPPAdapter/FinleyAdapterException.cpp   |    2 +-
 finley/src/CPPAdapter/FinleyAdapterException.h     |    2 +-
 finley/src/CPPAdapter/MeshAdapter.cpp              |   11 +-
 finley/src/CPPAdapter/MeshAdapter.h                |    8 +-
 finley/src/CPPAdapter/MeshAdapterFactory.cpp       |    8 +-
 finley/src/CPPAdapter/MeshAdapterFactory.h         |    2 +-
 finley/src/CPPAdapter/finleycpp.cpp                |   26 +-
 finley/src/CPPAdapter/system_dep.h                 |   17 +-
 finley/src/ElementFile.cpp                         |    5 +-
 finley/src/ElementFile.h                           |    2 +-
 finley/src/ElementFile_jacobians.cpp               |    6 +-
 finley/src/Finley.cpp                              |    2 +-
 finley/src/Finley.h                                |    2 +-
 finley/src/FinleyVersion.h                         |    4 +-
 finley/src/IndexList.cpp                           |    6 +-
 finley/src/IndexList.h                             |    2 +-
 finley/src/Mesh.cpp                                |    6 +-
 finley/src/Mesh.h                                  |    8 +-
 finley/src/Mesh_addPoints.cpp                      |    6 +-
 finley/src/Mesh_findMatchingFaces.cpp              |    5 +-
 finley/src/Mesh_getPattern.cpp                     |    6 +-
 finley/src/Mesh_glueFaces.cpp                      |    5 +-
 finley/src/Mesh_hex20.cpp                          |    6 +-
 finley/src/Mesh_hex8.cpp                           |    6 +-
 finley/src/Mesh_joinFaces.cpp                      |    6 +-
 finley/src/Mesh_merge.cpp                          |    6 +-
 finley/src/Mesh_optimizeDOFDistribution.cpp        |   22 +-
 finley/src/Mesh_read.cpp                           |    5 +-
 finley/src/Mesh_readGmsh.cpp                       | 1232 ++-
 finley/src/Mesh_rec4.cpp                           |    5 +-
 finley/src/Mesh_rec8.cpp                           |    5 +-
 finley/src/Mesh_write.cpp                          |    5 +-
 finley/src/NodeFile.cpp                            |    5 +-
 finley/src/NodeFile.h                              |    2 +-
 finley/src/NodeMapping.h                           |    2 +-
 finley/src/Quadrature.cpp                          |    2 +-
 finley/src/Quadrature.h                            |    2 +-
 finley/src/RectangularMesh.h                       |    2 +-
 finley/src/ReferenceElementSets.h                  |    2 +-
 finley/src/ReferenceElements.cpp                   |    2 +-
 finley/src/ReferenceElements.h                     |    2 +-
 finley/src/SConscript                              |    2 +-
 finley/src/ShapeFunctions.cpp                      |    2 +-
 finley/src/ShapeFunctions.h                        |    2 +-
 finley/src/Util.cpp                                |    5 +-
 finley/src/Util.h                                  |    2 +-
 finley/src/generateReferenceElementList.py         |    2 +-
 finley/test/MeshAdapterTestCase.cpp                |    5 +-
 finley/test/MeshAdapterTestCase.h                  |    2 +-
 finley/test/SConscript                             |    2 +-
 finley/test/finley_UnitTests.cpp                   |    2 +-
 finley/test/python/FCT_benchmark.py                |    4 +-
 finley/test/python/FCT_test0.py                    |    4 +-
 finley/test/python/FCT_test1.py                    |    4 +-
 finley/test/python/FCT_test2.py                    |    4 +-
 finley/test/python/OutTest.py                      |    4 +-
 finley/test/python/PoissonSolverTest.py            |    4 +-
 finley/test/python/RecTest.py                      |    4 +-
 finley/test/python/SConscript                      |    5 +-
 finley/test/python/axisymm-splitB.py               |    4 +-
 finley/test/python/blocktest.py                    |    4 +-
 finley/test/python/brick.py                        |    4 +-
 finley/test/python/coalgas.py                      |    4 +-
 finley/test/python/convection.py                   |    4 +-
 finley/test/python/damage.py                       |    4 +-
 finley/test/python/generate_dumps.py               |    4 +-
 finley/test/python/generate_meshes.py              |    4 +-
 finley/test/python/linearElastic.py                |    4 +-
 finley/test/python/localization.py                 |    4 +-
 finley/test/python/lumping_advection_test.py       |    4 +-
 finley/test/python/lumping_wave_test.py            |    4 +-
 finley/test/python/rayleigh_taylor_instabilty.py   |    4 +-
 finley/test/python/rectangle.py                    |    4 +-
 finley/test/python/run_amg.py                      |    4 +-
 finley/test/python/run_darcy.py                    |    4 +-
 finley/test/python/run_escriptOnFinley.py          |   10 +-
 finley/test/python/run_generators.py               |    4 +-
 finley/test/python/run_inputOutput.py              |    4 +-
 finley/test/python/run_linearPDEsOnFinley1_2D1.py  |    4 +-
 finley/test/python/run_linearPDEsOnFinley1_2D2.py  |    4 +-
 finley/test/python/run_linearPDEsOnFinley1_3D1.py  |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part1.py    |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part2.py    |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part3-1.py  |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part3-2.py  |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part3-3.py  |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part3-4.py  |    4 +-
 .../python/run_linearPDEsOnFinley1_3D2_part4.py    |    4 +-
 finley/test/python/run_linearPDEsOnFinley2.py      |    4 +-
 finley/test/python/run_linearPDEsOnFinley3.py      |    4 +-
 finley/test/python/run_linearPDEsOnFinleyMacro.py  |    4 +-
 finley/test/python/run_models.py                   |    4 +-
 finley/test/python/run_nlpde2dOnFinley.py          |    4 +-
 finley/test/python/run_nlpde3dOnFinley.py          |    4 +-
 finley/test/python/run_simplesolve.py              |    4 +-
 .../test/python/run_splitworldOnFinley.py          |   31 +-
 finley/test/python/run_utilOnFinley.py             |    8 +-
 finley/test/python/run_visualization_interface.py  |    4 +-
 finley/test/python/runcoalgas.py                   |    4 +-
 finley/test/python/seismic_wave.py                 |    4 +-
 finley/test/python/slip_stress_mesh_old.py         |    4 +-
 finley/test/python/slip_stress_old.py              |    4 +-
 finley/test/python/stokes_problems.py              |    4 +-
 finley/test/python/subduction1.py                  |    4 +-
 finley/test/python/subduction1_gen.py              |    4 +-
 finley/test/python/time_chunks.py                  |    4 +-
 finley/test/python/tp.py                           |    4 +-
 modellib/py_src/SConscript                         |    2 +-
 modellib/py_src/flow.py                            |    4 +-
 modellib/py_src/geometry.py                        |    4 +-
 modellib/py_src/input.py                           |    4 +-
 modellib/py_src/materials.py                       |    4 +-
 modellib/py_src/mechanics.py                       |    4 +-
 modellib/py_src/probe.py                           |    4 +-
 modellib/py_src/temperature.py                     |    4 +-
 modellib/py_src/tsunami.py.old                     |    4 +-
 modellib/py_src/visualization.py                   |    4 +-
 modellib/test/python/SConscript                    |    2 +-
 modellib/test/python/drucker_prager.py             |    4 +-
 modellib/test/python/run_convection.py             |    4 +-
 modellib/test/python/run_domainreaders.py          |    4 +-
 modellib/test/python/run_flow.py                   |    4 +-
 modellib/test/python/run_temp.py                   |    4 +-
 paso/profiling/Paso_tests.cpp                      |    2 +-
 paso/profiling/Paso_tests.h                        |    2 +-
 paso/profiling/SConscript                          |    2 +-
 paso/src/AMG.cpp                                   |    2 +-
 paso/src/AMG_Interpolation.cpp                     |    2 +-
 paso/src/AMG_Prolongation.cpp                      |    2 +-
 paso/src/AMG_Restriction.cpp                       |    2 +-
 paso/src/AMG_Root.cpp                              |    2 +-
 paso/src/AML.cpp.old                               |    4 +-
 paso/src/BOOMERAMG.cpp                             |    2 +-
 paso/src/BOOMERAMG.h                               |    2 +-
 paso/src/BiCGStab.cpp                              |    2 +-
 paso/src/BlockOps.h                                |    2 +-
 paso/src/Coupler.cpp                               |    2 +-
 paso/src/Coupler.h                                 |    2 +-
 paso/src/Distribution.cpp                          |    2 +-
 paso/src/Distribution.h                            |    2 +-
 paso/src/FCT_Solver.cpp                            |    2 +-
 paso/src/FCT_Solver.h                              |    2 +-
 paso/src/FluxLimiter.cpp                           |    2 +-
 paso/src/FluxLimiter.h                             |    2 +-
 paso/src/Functions.cpp                             |    2 +-
 paso/src/Functions.h                               |    2 +-
 paso/src/GMRES.cpp                                 |    2 +-
 paso/src/GMRES2.cpp                                |    2 +-
 paso/src/GSMPI.cpp.old                             |    2 +-
 paso/src/ILU.cpp                                   |    2 +-
 paso/src/LocalAMG.cpp                              |    2 +-
 paso/src/LocalAMG_Prolongation.cpp                 |    2 +-
 paso/src/MINRES.cpp                                |    2 +-
 paso/src/MKL.cpp                                   |    2 +-
 paso/src/MKL.h                                     |    2 +-
 paso/src/MergedSolver.cpp                          |    2 +-
 paso/src/MergedSolver.h                            |    2 +-
 paso/src/NewtonGMRES.cpp                           |    2 +-
 paso/src/Options.cpp                               |    2 +-
 paso/src/Options.h                                 |    2 +-
 paso/src/PCG.cpp                                   |    2 +-
 paso/src/Paso.h                                    |    2 +-
 paso/src/PasoUtil.cpp                              |    2 +-
 paso/src/PasoUtil.h                                |    2 +-
 paso/src/Pattern.cpp                               |    2 +-
 paso/src/Pattern.h                                 |    2 +-
 paso/src/Pattern_mis.cpp                           |    2 +-
 paso/src/Pattern_reduceBandwidth.cpp               |    2 +-
 paso/src/Preconditioner.cpp                        |    2 +-
 paso/src/Preconditioner.h                          |    2 +-
 paso/src/RILU.cpp                                  |    2 +-
 paso/src/ReactiveSolver.cpp                        |    2 +-
 paso/src/ReactiveSolver.h                          |    2 +-
 paso/src/SConscript                                |    2 +-
 paso/src/SchurComplement.cpp                       |    2 +-
 paso/src/SharedComponents.h                        |    2 +-
 paso/src/Smoother.cpp                              |    2 +-
 paso/src/Solver.cpp                                |    8 +-
 paso/src/Solver.h                                  |    2 +-
 paso/src/Solver_Function.cpp                       |    2 +-
 paso/src/Solver_applyBlockDiagonalMatrix.cpp.old   |    2 +-
 paso/src/SparseMatrix.cpp                          |    2 +-
 paso/src/SparseMatrix.h                            |    2 +-
 paso/src/SparseMatrix_MatrixMatrix.cpp             |    2 +-
 paso/src/SparseMatrix_MatrixMatrixTranspose.cpp    |    2 +-
 paso/src/SparseMatrix_MatrixVector.cpp             |    2 +-
 paso/src/SparseMatrix_getSubmatrix.cpp             |    2 +-
 paso/src/SparseMatrix_nullifyRowsAndCols.cpp       |    2 +-
 paso/src/SparseMatrix_saveHB.cpp                   |    2 +-
 paso/src/SystemMatrix.cpp                          |    2 +-
 paso/src/SystemMatrix.h                            |    2 +-
 paso/src/SystemMatrixPattern.cpp                   |    2 +-
 paso/src/SystemMatrixPattern.h                     |    2 +-
 paso/src/SystemMatrixPattern_unrollBlocks.cpp      |    2 +-
 paso/src/SystemMatrix_MatrixVector.cpp             |    2 +-
 paso/src/SystemMatrix_copyRemoteCoupleBlock.cpp    |    2 +-
 paso/src/SystemMatrix_debug.cpp                    |    2 +-
 paso/src/SystemMatrix_extendedRows.cpp             |    2 +-
 paso/src/SystemMatrix_loadMM.cpp                   |    2 +-
 paso/src/SystemMatrix_mergeMainAndCouple.cpp       |    2 +-
 paso/src/TFQMR.cpp                                 |    2 +-
 paso/src/Transport.cpp                             |    2 +-
 paso/src/Transport.h                               |    2 +-
 paso/src/Transport_solve.cpp                       |    2 +-
 paso/src/UMFPACK.cpp                               |    2 +-
 paso/src/UMFPACK.h                                 |    2 +-
 paso/src/mmio.cpp                                  |    2 +-
 paso/src/mmio.h                                    |    2 +-
 paso/src/performance.cpp                           |    2 +-
 paso/src/performance.h                             |    2 +-
 paso/src/solve.cpp                                 |    2 +-
 pasowrap/py_src/SConscript                         |    2 +-
 pasowrap/py_src/__init__.py                        |    4 +-
 pasowrap/py_src/pasowrap.py                        |    4 +-
 pasowrap/src/PasoException.cpp                     |    2 +-
 pasowrap/src/PasoException.h                       |    2 +-
 pasowrap/src/SConscript                            |    2 +-
 pasowrap/src/SystemMatrixAdapter.cpp               |    6 +-
 pasowrap/src/SystemMatrixAdapter.h                 |    2 +-
 pasowrap/src/TransportProblemAdapter.cpp           |    6 +-
 pasowrap/src/TransportProblemAdapter.h             |    2 +-
 pasowrap/src/pasowrapcpp.cpp                       |    4 +-
 pasowrap/src/system_dep.h                          |   17 +-
 pycad/py_src/SConscript                            |    2 +-
 pycad/py_src/Triangle.py                           |    4 +-
 pycad/py_src/__init__.py                           |    4 +-
 pycad/py_src/design.py                             |    6 +-
 pycad/py_src/extras.py                             |    4 +-
 pycad/py_src/gmsh.py                               |    4 +-
 pycad/py_src/primitives.py                         |    4 +-
 pycad/py_src/shapes.py                             |    4 +-
 pycad/py_src/transformations.py                    |    4 +-
 pycad/test/python/SConscript                       |   10 +-
 pycad/test/python/run_pycad_test.py                |    4 +-
 pythonMPI/src/SConscript                           |    2 +-
 pythonMPI/src/ScriptMPI.cpp                        |    2 +-
 pythonMPI/src/ScriptMPIredirect.cpp                |    2 +-
 ripley/py_src/MultiResolutionDomain.py             |   96 +
 ripley/py_src/SConscript                           |    2 +-
 ripley/py_src/__init__.py                          |    6 +-
 ripley/src/AbstractAssembler.h                     |    2 +-
 ripley/src/Brick.cpp                               |  262 +-
 ripley/src/Brick.h                                 |   10 +-
 ripley/src/DefaultAssembler2D.cpp                  | 3303 +++----
 ripley/src/DefaultAssembler2D.h                    |    2 +-
 ripley/src/DefaultAssembler3D.cpp                  | 9383 ++++++++++----------
 ripley/src/DefaultAssembler3D.h                    |    2 +-
 ripley/src/LameAssembler2D.cpp                     |  180 +-
 ripley/src/LameAssembler2D.h                       |    2 +-
 ripley/src/LameAssembler3D.cpp                     |  608 +-
 ripley/src/LameAssembler3D.h                       |    2 +-
 ripley/src/MultiBrick.cpp                          | 1563 ++++
 ripley/src/MultiBrick.h                            |  204 +
 ripley/src/MultiRectangle.cpp                      |  963 ++
 ripley/src/MultiRectangle.h                        |  177 +
 ripley/src/Rectangle.cpp                           |  178 +-
 ripley/src/Rectangle.h                             |   46 +-
 ripley/src/Ripley.h                                |    2 +-
 ripley/src/RipleyDomain.cpp                        |   11 +-
 ripley/src/RipleyDomain.h                          |   25 +-
 ripley/src/RipleyException.cpp                     |    2 +-
 ripley/src/RipleyException.h                       |    2 +-
 ripley/src/RipleySystemMatrix.cu                   |    2 +-
 ripley/src/RipleySystemMatrix.h                    |    2 +-
 ripley/src/SConscript                              |    6 +-
 ripley/src/WaveAssembler2D.cpp                     |  105 +-
 ripley/src/WaveAssembler2D.h                       |   16 +-
 ripley/src/WaveAssembler3D.cpp                     |  623 +-
 ripley/src/WaveAssembler3D.h                       |   16 +-
 ripley/src/blocktools.cpp                          |    2 +-
 ripley/src/blocktools.h                            |    2 +-
 ripley/src/blocktools2.cpp                         |    2 +-
 ripley/src/domainhelpers.cpp                       |    6 +-
 ripley/src/domainhelpers.h                         |    2 +-
 ripley/src/generate_assemblage_cpp.py              |    2 +-
 ripley/src/ripleycpp.cpp                           |  363 +-
 ripley/src/system_dep.h                            |   17 +-
 ripley/test/SConscript                             |    2 +-
 ripley/test/SystemMatrixTestCase.cpp               |    2 +-
 ripley/test/SystemMatrixTestCase.h                 |    2 +-
 ripley/test/python/SConscript                      |    4 +-
 .../test/python/run_customAssemblersOnMultiRes.py  |   83 +
 ripley/test/python/run_customAssemblersOnRipley.py |  245 +-
 ripley/test/python/run_diracOnMultiRes.py          |  142 +
 ripley/test/python/run_diracOnRipley.py            |   19 +-
 ripley/test/python/run_escriptOnMultiResolution.py |  395 +
 ripley/test/python/run_escriptOnRipley.py          |   13 +-
 ...PDEsOnRipley.py => run_linearPDEsOnMultiRes.py} |   17 +-
 ripley/test/python/run_linearPDEsOnRipley.py       |    4 +-
 ...DEOnRipley.py => run_nonlinearPDEOnMultiRes.py} |   16 +-
 ripley/test/python/run_nonlinearPDEOnRipley.py     |    4 +-
 ...WriteOnRipley.py => run_readWriteOnMultiRes.py} |  178 +-
 ripley/test/python/run_readWriteOnRipley.py        |    4 +-
 ...lveOnRipley.py => run_simplesolveOnMultiRes.py} |   18 +-
 ripley/test/python/run_simplesolveOnRipley.py      |    4 +-
 .../{run_utilOnRipley.py => run_utilOnMultiRes.py} |   25 +-
 ripley/test/python/run_utilOnRipley.py             |    9 +-
 ripley/test/ripley_UnitTest.cpp                    |    2 +-
 run-escript.in                                     |   29 +-
 scons/badger_options.py                            |    2 +-
 scons/cgisrv3_options.py                           |    2 +-
 scons/cgisrv6_options.py                           |    2 +-
 scons/copper_options.py                            |    2 +-
 scons/epicuser_options.py                          |    2 +-
 scons/ferret_options.py                            |    2 +-
 scons/gerbil_options.py                            |    2 +-
 scons/guineapig_intel_noomp_options.py             |    2 +-
 scons/guineapig_intel_options.py                   |    2 +-
 scons/guineapig_options.py                         |    4 +-
 scons/guineapig_py3_options.py                     |    2 +-
 scons/hamster_options.py                           |    4 +-
 ...homebrew_10.10_options.py => magnus_options.py} |  141 +-
 scons/mara_options.py                              |    2 +-
 scons/mole_clang_options.py                        |    4 +-
 scons/mole_gcc_options.py                          |  240 -
 scons/porcupine_options.py                         |    2 +-
 scons/raijin_options.py                            |    2 +-
 scons/sage_options.py                              |    4 +-
 scons/sage_py3_options.py                          |    2 +-
 ...omp_options.py => savanna_ice_noomp_options.py} |    4 +-
 .../{badger_options.py => savanna_ice_options.py}  |   14 +-
 scons/savanna_noomp_options.py                     |    2 +-
 scons/savanna_options.py                           |   37 +-
 scons/squirrel_options.py                          |    2 +-
 scons/standalone_options.py                        |    2 +-
 scons/templates/centos7_0_options.py               |    2 +-
 scons/templates/fedora21_5_options.py              |    2 +-
 scons/templates/freebsd10_0_options.py             |    2 +-
 scons/templates/homebrew_10.10_options.py          |    2 +-
 scons/templates/homebrew_options.py                |    2 +-
 scons/templates/jessie_mpi_options.py              |    2 +-
 scons/templates/jessie_options.py                  |   16 +-
 scons/templates/jessie_py3_mpi_options.py          |    2 +-
 scons/templates/jessie_py3_options.py              |    2 +-
 scons/templates/macports_10.10_options.py          |    2 +-
 scons/templates/macports_options.py                |    2 +-
 scons/templates/opensuse13_2_options.py            |    2 +-
 scons/templates/trusty_options.py                  |    2 +-
 scons/templates/utopic_options.py                  |    2 +-
 scons/templates/wheezy_mpi_options.py              |    2 +-
 scons/templates/wheezy_options.py                  |    2 +-
 scons/templates/wheezy_py3_mpi_options.py          |    2 +-
 scons/templates/wheezy_py3_options.py              |    2 +-
 scons/templates/windows_intelc_options.py          |    2 +-
 scons/templates/windows_msvc90_options.py          |    2 +-
 scons/templates/windows_options.py                 |    2 +-
 scons/vayu_options.py                              |    2 +-
 scons/vm_options.py                                |    2 +-
 scons/vmw_options.py                               |    2 +-
 scripts/extracttests.sh                            |   80 +-
 site_scons/dependencies.py                         |   15 +-
 site_scons/extractdebbuild.py                      |    4 +-
 site_scons/grouptest.py                            |   33 +-
 site_scons/site_init.py                            |    9 +-
 speckley/py_src/SConscript                         |    2 +-
 speckley/py_src/__init__.py                        |    4 +-
 speckley/src/AbstractAssembler.cpp                 |    7 +-
 speckley/src/AbstractAssembler.h                   |    2 +-
 speckley/src/Brick.cpp                             |  579 +-
 speckley/src/Brick.h                               |   17 +-
 speckley/src/BrickGradients.cpp                    |  736 +-
 speckley/src/BrickIntegrals.cpp                    |   18 +
 .../{BrickIntegrals.cpp => BrickReductions.cpp}    |  170 +-
 speckley/src/CrossDomainCoupler.cpp                |    7 +-
 speckley/src/CrossDomainCoupler.h                  |    2 +-
 speckley/src/DefaultAssembler2D.cpp                |    7 +-
 speckley/src/DefaultAssembler2D.h                  |    2 +-
 speckley/src/DefaultAssembler3D.cpp                |    7 +-
 speckley/src/DefaultAssembler3D.h                  |    2 +-
 speckley/src/Rectangle.cpp                         |  324 +-
 speckley/src/Rectangle.h                           |   17 +-
 speckley/src/RectangleGradients.cpp                |  516 +-
 speckley/src/RectangleIntegrals.cpp                |   18 +
 speckley/src/RectangleReductions.cpp               |  200 +
 speckley/src/SConscript                            |    8 +-
 speckley/src/Speckley.h                            |    2 +-
 speckley/src/SpeckleyDomain.cpp                    |  103 +-
 speckley/src/SpeckleyDomain.h                      |   33 +-
 speckley/src/SpeckleyException.cpp                 |    6 +-
 speckley/src/SpeckleyException.h                   |    2 +-
 ...{DefaultAssembler2D.cpp => WaveAssembler2D.cpp} |  259 +-
 .../{DefaultAssembler2D.h => WaveAssembler2D.h}    |   72 +-
 ...{DefaultAssembler3D.cpp => WaveAssembler3D.cpp} |  393 +-
 .../{DefaultAssembler3D.h => WaveAssembler3D.h}    |   66 +-
 speckley/src/domainhelpers.cpp                     |    6 +-
 speckley/src/domainhelpers.h                       |    2 +-
 speckley/src/lagrange_functions.h                  |    2 +-
 speckley/src/speckleycpp.cpp                       |   26 +-
 speckley/src/system_dep.h                          |   17 +-
 speckley/test/SConscript                           |    2 +-
 speckley/test/python/SConscript                    |    4 +-
 speckley/test/python/run_SpeckleyRipleyCoupler.py  |   32 +-
 .../test/python/run_customAssemblersOnSpeckley.py  |  269 +
 speckley/test/python/run_diracOnSpeckley.py        |    4 +-
 speckley/test/python/run_readWriteOnSpeckley.py    |    4 +-
 speckley/test/python/run_specialOnSpeckley.py      |   41 +-
 tools/escriptconvert/SConscript                    |    2 +-
 tools/escriptconvert/escriptconvert.cpp            |    2 +-
 tools/escriptconvert/esdcreate.cpp                 |    2 +-
 {pasowrap/py_src => tools/overlord}/SConscript     |   18 +-
 tools/overlord/overlord.c                          |   70 +
 tools/testrunner.py                                |   80 +-
 weipa/py_src/SConscript                            |    2 +-
 weipa/py_src/__init__.py                           |    4 +-
 weipa/src/DataVar.cpp                              |    6 +-
 weipa/src/DataVar.h                                |    2 +-
 weipa/src/DomainChunk.h                            |    2 +-
 weipa/src/ElementData.h                            |    2 +-
 weipa/src/EscriptDataset.cpp                       |    6 +-
 weipa/src/EscriptDataset.h                         |    2 +-
 weipa/src/FinleyDomain.cpp                         |    6 +-
 weipa/src/FinleyDomain.h                           |    2 +-
 weipa/src/FinleyElements.cpp                       |    6 +-
 weipa/src/FinleyElements.h                         |    2 +-
 weipa/src/FinleyNodes.cpp                          |    5 +-
 weipa/src/FinleyNodes.h                            |    2 +-
 weipa/src/NodeData.h                               |    2 +-
 weipa/src/RipleyDomain.cpp                         |    5 +-
 weipa/src/RipleyDomain.h                           |    2 +-
 weipa/src/RipleyElements.cpp                       |  117 +-
 weipa/src/RipleyElements.h                         |    2 +-
 weipa/src/RipleyNodes.cpp                          |    5 +-
 weipa/src/RipleyNodes.h                            |    2 +-
 weipa/src/SConscript                               |    2 +-
 weipa/src/SpeckleyDomain.cpp                       |   10 +-
 weipa/src/SpeckleyDomain.h                         |    2 +-
 weipa/src/SpeckleyElements.cpp                     |   14 +-
 weipa/src/SpeckleyElements.h                       |    2 +-
 weipa/src/SpeckleyNodes.cpp                        |    5 +-
 weipa/src/SpeckleyNodes.h                          |    2 +-
 weipa/src/VisItControl.cpp                         |    5 +-
 weipa/src/VisItControl.h                           |    2 +-
 weipa/src/VisItData.cpp                            |    6 +-
 weipa/src/VisItData.h                              |    2 +-
 weipa/src/weipa.h                                  |    2 +-
 weipa/src/weipacpp.cpp                             |    5 +-
 weipa/test/EscriptDatasetTestCase.cpp              |    9 +-
 weipa/test/EscriptDatasetTestCase.h                |    2 +-
 weipa/test/SConscript                              |    2 +-
 weipa/test/python/SConscript                       |    4 +-
 weipa/test/python/run_savesilo_tests.py            |    4 +-
 weipa/test/python/run_savevtk_tests.py             |    4 +-
 weipa/test/weipa_UnitTest.cpp                      |    6 +-
 1135 files changed, 24369 insertions(+), 15959 deletions(-)

diff --git a/SConstruct b/SConstruct
index f0b3d53..70d155e 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -46,7 +46,7 @@ if not options_file:
 if not os.path.isfile(options_file):
     print("\nWARNING:\nOptions file %s" % options_file)
     print("not found! Default options will be used which is most likely suboptimal.")
-    print("We recommend that you copy the most relavent options file in the scons/os/")
+    print("We recommend that you copy the most relavent options file in the scons/template/")
     print("subdirectory and customize it to your needs.\n")
     options_file = None
 
@@ -75,6 +75,7 @@ vars.AddVariables(
   ('cc_debug', 'Additional (C and C++) flags for a debug build', 'default'),
   ('cxx_extra', 'Extra C++ compiler flags', ''),
   ('cpp_flags', 'C Pre-processor flags', ''),
+  ('cpp_extra', 'Extra C Pre-processor flags', ''),
   ('ld_extra', 'Extra linker flags', ''),
   ('nvcc', 'Path to CUDA compiler', 'default'),
   ('nvccflags', 'Base CUDA compiler flags', 'default'),
@@ -94,7 +95,7 @@ vars.AddVariables(
   ('mpi_prefix', 'Prefix/Paths of MPI installation', default_prefix),
   ('mpi_libs', 'MPI shared libraries to link with', ['mpi']),
   BoolVariable('cuda', 'Enable GPU code with CUDA (requires thrust)', False),
-  ('thrust_prefix', 'Prefix/Paths to NVidia thrust installation', default_prefix),
+  ('cuda_prefix', 'Prefix/Paths to NVidia CUDA installation', default_prefix),
   BoolVariable('netcdf', 'Enable netCDF file support', False),
   ('netcdf_prefix', 'Prefix/Paths of netCDF installation', default_prefix),
   ('netcdf_libs', 'netCDF libraries to link with', ['netcdf_c++', 'netcdf']),
@@ -144,7 +145,6 @@ vars.AddVariables(
   ('pythonlibpath', 'Path to the python library. (You should not need to set this unless your python has moved)',''),
   ('pythonincpath','Path to python include files. (You should not need to set this unless your python has moved',''),
   BoolVariable('longindices', 'use long indices (for very large matrices)', False),
-  BoolVariable('BADPYTHONMACROS','Extra \#include to get around a python bug.', True),
   BoolVariable('compressed_files','Enables reading from compressed binary files', True),
   ('compression_libs', 'Compression libraries to link with', ['boost_iostreams']),
   BoolVariable('papi', 'Enable PAPI', False),
@@ -297,14 +297,12 @@ if env['omp_ldflags'] == 'default': env['omp_ldflags'] = omp_ldflags
 if env['cxx_extra'] != '': env.Append(CXXFLAGS = env['cxx_extra'])
 if env['ld_extra']  != '': env.Append(LINKFLAGS = env['ld_extra'])
 if env['cpp_flags'] != '': env.Append(CPPFLAGS = env['cpp_flags'])
+if env['cpp_extra'] != '': env.Append(CPPFLAGS = " "+env['cpp_extra'])
 
 if env['nvccflags'] != 'default':
     env['NVCCFLAGS'] = env['nvccflags']
     env['SHNVCCFLAGS'] = env['nvccflags'] + ' -shared'
 
-if env['BADPYTHONMACROS']:
-    env.Append(CPPDEFINES = ['BADPYTHONMACROS'])
-
 if env['longindices']:
     env.Append(CPPDEFINES = ['ESYS_INDEXTYPE_LONG'])
 
@@ -443,6 +441,10 @@ for key in set(env_export):
     except KeyError:
         pass
 
+for key in os.environ.keys():
+    if key.startswith("SLURM_"):
+        env['ENV'][key] = os.environ[key]
+
 try:
     env.PrependENVPath(LD_LIBRARY_PATH_KEY, os.environ[LD_LIBRARY_PATH_KEY])
 except KeyError:
@@ -501,6 +503,7 @@ env=checkBoost(env)
 ######## NVCC version (optional)
 if env['cuda']:
     env=checkCudaVersion(env)
+    env=checkCUDA(env)
 
 ######## numpy (required) and numpy headers (optional)
 env=checkNumpy(env)
@@ -545,6 +548,7 @@ if not env['verbose']:
 # remove obsolete files
 if not env['usempi']:
     Execute(Delete(os.path.join(env['libinstall'], 'pythonMPI')))
+    Execute(Delete(os.path.join(env['bininstall'], 'escript-overlord')))
     Execute(Delete(os.path.join(env['libinstall'], 'pythonMPIredirect')))
 
 from grouptest import *
@@ -568,6 +572,7 @@ Export(
 
 #do not auto build
 env.SConscript(dirs = ['tools/escriptconvert'], variant_dir='$BUILD_DIR/$PLATFORM/tools/escriptconvert', duplicate=0)
+env.SConscript(dirs = ['tools/overlord'], variant_dir='$BUILD_DIR/$PLATFORM/tools/overlord', duplicate=0)
 env.SConscript(dirs = ['paso/src'], variant_dir='$BUILD_DIR/$PLATFORM/paso', duplicate=0)
 env.SConscript(dirs = ['weipa/src'], variant_dir='$BUILD_DIR/$PLATFORM/weipa', duplicate=0)
 env.SConscript(dirs = ['escript/py_src'], variant_dir='$BUILD_DIR/$PLATFORM/escript', duplicate=0)
@@ -656,7 +661,8 @@ if 'speckley' in env['domains']: build_all_list += ['build_speckley']
 build_all_list += ['build_weipa']
 if not IS_WINDOWS and 'finley' in env['domains']:
     build_all_list += ['build_escriptreader']
-if env['usempi']:   build_all_list += ['build_pythonMPI']
+if env['usempi']:
+    build_all_list += ['build_pythonMPI', 'build_overlord']
 env.Alias('build_all', build_all_list)
 
 install_all_list = []
@@ -675,7 +681,8 @@ if not IS_WINDOWS and 'finley' in env['domains']:
 install_all_list += ['install_downunder_py']
 install_all_list += ['install_modellib_py']
 install_all_list += ['install_pycad_py']
-if env['usempi']:   install_all_list += ['install_pythonMPI']
+if env['usempi']:
+    install_all_list += ['install_pythonMPI', 'install_overlord']
 env.Alias('install_all', install_all_list)
 
 # Default target is install
@@ -691,6 +698,7 @@ env.Alias('run_tests', ['install_all'])
 env.Alias('all_tests', ['install_all', 'run_tests', 'py_tests'])
 env.Alias('build_full',['install_all','build_tests','build_py_tests'])
 env.Alias('build_PasoTests','$BUILD_DIR/$PLATFORM/paso/profiling/PasoTests')
+Requires('py_tests', 'install_all')
 
 ##################### Targets to build the documentation #####################
 
diff --git a/cusplibrary/SConscript b/cusplibrary/SConscript
index 539f8a1..ab92952 100644
--- a/cusplibrary/SConscript
+++ b/cusplibrary/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2014 by University of Queensland
+# Copyright (c) 2014-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/cusplibrary/cusp/array2d.h b/cusplibrary/cusp/array2d.h
index e0b2187..f3c7ce5 100644
--- a/cusplibrary/cusp/array2d.h
+++ b/cusplibrary/cusp/array2d.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 /*! \file array2d.h
  *  \brief Two-dimensional array
  */
diff --git a/cusplibrary/cusp/cds_matrix.h b/cusplibrary/cusp/cds_matrix.h
index 2ffb882..3f263f3 100644
--- a/cusplibrary/cusp/cds_matrix.h
+++ b/cusplibrary/cusp/cds_matrix.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
- *
- * Copyright (c) 2014 by University of Queensland
- * http://www.uq.edu.au
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
  *
- * Primary Business: Queensland, Australia
- * Licensed under the Open Software License version 3.0
- * http://www.opensource.org/licenses/osl-3.0.php
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
  *
- * Development until 2012 by Earth Systems Science Computational Center (ESSCC)
- * Development 2012-2013 by School of Earth Sciences
- * Development from 2014 by Centre for Geoscience Computing (GeoComp)
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
- *****************************************************************************/
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 /*! \file cds_matrix.h
  *  \brief Column Diagonal Block matrix format.
diff --git a/cusplibrary/cusp/complex.h b/cusplibrary/cusp/complex.h
index 3a291d6..9aac9de 100644
--- a/cusplibrary/cusp/complex.h
+++ b/cusplibrary/cusp/complex.h
@@ -54,6 +54,13 @@
  * 
 */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 /*! \file complex.h
  *  \brief Complex numbers
  */
diff --git a/cusplibrary/cusp/detail/cds_matrix.inl b/cusplibrary/cusp/detail/cds_matrix.inl
index 7ea3876..92d2ab1 100644
--- a/cusplibrary/cusp/detail/cds_matrix.inl
+++ b/cusplibrary/cusp/detail/cds_matrix.inl
@@ -1,17 +1,19 @@
-/*****************************************************************************
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
  *
- * Copyright (c) 2014 by University of Queensland
- * http://www.uq.edu.au
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
  *
- * Primary Business: Queensland, Australia
- * Licensed under the Open Software License version 3.0
- * http://www.opensource.org/licenses/osl-3.0.php
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Development until 2012 by Earth Systems Science Computational Center (ESSCC)
- * Development 2012-2013 by School of Earth Sciences
- * Development from 2014 by Centre for Geoscience Computing (GeoComp)
- *
- *****************************************************************************/
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #include <cusp/convert.h>
 #include <cusp/detail/utils.h>
diff --git a/cusplibrary/cusp/detail/copy.inl b/cusplibrary/cusp/detail/copy.inl
index d9d2649..b886ccf 100644
--- a/cusplibrary/cusp/detail/copy.inl
+++ b/cusplibrary/cusp/detail/copy.inl
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #include <cusp/format.h>
 
 // TODO replace with detail/array2d_utils.h or something
diff --git a/cusplibrary/cusp/detail/device/conversion.h b/cusplibrary/cusp/detail/device/conversion.h
index 790d417..aac68ee 100644
--- a/cusplibrary/cusp/detail/device/conversion.h
+++ b/cusplibrary/cusp/detail/device/conversion.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/device/convert.h b/cusplibrary/cusp/detail/device/convert.h
index 9ad7341..4c8ad5b 100644
--- a/cusplibrary/cusp/detail/device/convert.h
+++ b/cusplibrary/cusp/detail/device/convert.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/device/multiply.h b/cusplibrary/cusp/detail/device/multiply.h
index 3dc4fca..453d135 100644
--- a/cusplibrary/cusp/detail/device/multiply.h
+++ b/cusplibrary/cusp/detail/device/multiply.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #pragma once
 
 #include <cusp/format.h>
diff --git a/cusplibrary/cusp/detail/device/spmv/cds.h b/cusplibrary/cusp/detail/device/spmv/cds.h
index e5447e9..1d58fe1 100644
--- a/cusplibrary/cusp/detail/device/spmv/cds.h
+++ b/cusplibrary/cusp/detail/device/spmv/cds.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/device/spmv/cds_symmetric.h b/cusplibrary/cusp/detail/device/spmv/cds_symmetric.h
index c8fc77c..99d8d33 100644
--- a/cusplibrary/cusp/detail/device/spmv/cds_symmetric.h
+++ b/cusplibrary/cusp/detail/device/spmv/cds_symmetric.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/device/transposed_multiply.h b/cusplibrary/cusp/detail/device/transposed_multiply.h
index fea9206..9ea68df 100644
--- a/cusplibrary/cusp/detail/device/transposed_multiply.h
+++ b/cusplibrary/cusp/detail/device/transposed_multiply.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/device/transposed_spmv/cds.h b/cusplibrary/cusp/detail/device/transposed_spmv/cds.h
index 854be8e..d0b5964 100644
--- a/cusplibrary/cusp/detail/device/transposed_spmv/cds.h
+++ b/cusplibrary/cusp/detail/device/transposed_spmv/cds.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/device/transposed_spmv/dia.h b/cusplibrary/cusp/detail/device/transposed_spmv/dia.h
index 372b9f2..bf15f75 100644
--- a/cusplibrary/cusp/detail/device/transposed_spmv/dia.h
+++ b/cusplibrary/cusp/detail/device/transposed_spmv/dia.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/dispatch/multiply.h b/cusplibrary/cusp/detail/dispatch/multiply.h
index a60b031..8c4f30f 100644
--- a/cusplibrary/cusp/detail/dispatch/multiply.h
+++ b/cusplibrary/cusp/detail/dispatch/multiply.h
@@ -13,7 +13,14 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-    
+
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #include <cusp/array1d.h>
 //MW: if device is not cuda then do not include cuda stuff and redirect device multiply to host
 #include <cusp/detail/host/multiply.h>
diff --git a/cusplibrary/cusp/detail/format_utils.inl b/cusplibrary/cusp/detail/format_utils.inl
index 3688168..4f821c0 100644
--- a/cusplibrary/cusp/detail/format_utils.inl
+++ b/cusplibrary/cusp/detail/format_utils.inl
@@ -13,7 +13,14 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-    
+
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #include <cusp/copy.h>
 #include <cusp/format.h>
 #include <cusp/array1d.h>
diff --git a/cusplibrary/cusp/detail/host/conversion.h b/cusplibrary/cusp/detail/host/conversion.h
index ecb4f02..294a57e 100644
--- a/cusplibrary/cusp/detail/host/conversion.h
+++ b/cusplibrary/cusp/detail/host/conversion.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 
 
 #pragma once
diff --git a/cusplibrary/cusp/detail/host/convert.h b/cusplibrary/cusp/detail/host/convert.h
index a187be4..ce437f0 100644
--- a/cusplibrary/cusp/detail/host/convert.h
+++ b/cusplibrary/cusp/detail/host/convert.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/host/multiply.h b/cusplibrary/cusp/detail/host/multiply.h
index 05c1148..17689a2 100644
--- a/cusplibrary/cusp/detail/host/multiply.h
+++ b/cusplibrary/cusp/detail/host/multiply.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #pragma once
 
 #include <cusp/format.h>
diff --git a/cusplibrary/cusp/detail/host/spmv.h b/cusplibrary/cusp/detail/host/spmv.h
index c66dc89..ae1394e 100644
--- a/cusplibrary/cusp/detail/host/spmv.h
+++ b/cusplibrary/cusp/detail/host/spmv.h
@@ -1,3 +1,10 @@
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #pragma once
 
 #include <thrust/functional.h>
diff --git a/cusplibrary/cusp/detail/host/transposed_multiply.h b/cusplibrary/cusp/detail/host/transposed_multiply.h
index 4868cee..f7805a8 100644
--- a/cusplibrary/cusp/detail/host/transposed_multiply.h
+++ b/cusplibrary/cusp/detail/host/transposed_multiply.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/host/transposed_spmv.h b/cusplibrary/cusp/detail/host/transposed_spmv.h
index b364905..11e660c 100644
--- a/cusplibrary/cusp/detail/host/transposed_spmv.h
+++ b/cusplibrary/cusp/detail/host/transposed_spmv.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #pragma once
 
diff --git a/cusplibrary/cusp/detail/multiply.inl b/cusplibrary/cusp/detail/multiply.inl
index 9765e89..7bb39a2 100644
--- a/cusplibrary/cusp/detail/multiply.inl
+++ b/cusplibrary/cusp/detail/multiply.inl
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #include <cusp/detail/dispatch/multiply.h>
 
 #include <cusp/linear_operator.h>
diff --git a/cusplibrary/cusp/dia_matrix.h b/cusplibrary/cusp/dia_matrix.h
index e605330..8f590dc 100644
--- a/cusplibrary/cusp/dia_matrix.h
+++ b/cusplibrary/cusp/dia_matrix.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 /*! \file dia_matrix.h
  *  \brief Diagonal matrix format.
  */
diff --git a/cusplibrary/cusp/format.h b/cusplibrary/cusp/format.h
index c1dbf24..5ceb71a 100644
--- a/cusplibrary/cusp/format.h
+++ b/cusplibrary/cusp/format.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 
 /*! \file format.h
  *  \brief Format types
diff --git a/cusplibrary/cusp/gallery/random.h b/cusplibrary/cusp/gallery/random.h
index 1b5ebe9..3075b0d 100644
--- a/cusplibrary/cusp/gallery/random.h
+++ b/cusplibrary/cusp/gallery/random.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 /*! \file random.h
  *  \brief Random matrix generators
  */
diff --git a/cusplibrary/cusp/graph/detail/dispatch/hilbert_curve.h b/cusplibrary/cusp/graph/detail/dispatch/hilbert_curve.h
index 55464ba..585fb87 100644
--- a/cusplibrary/cusp/graph/detail/dispatch/hilbert_curve.h
+++ b/cusplibrary/cusp/graph/detail/dispatch/hilbert_curve.h
@@ -13,7 +13,14 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-    
+
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #include <cusp/memory.h>
 #include <cusp/graph/detail/host/hilbert_curve.h>
 #include <cusp/graph/detail/device/hilbert_curve.h>
diff --git a/cusplibrary/cusp/graph/detail/host/hilbert_curve.h b/cusplibrary/cusp/graph/detail/host/hilbert_curve.h
index a469d20..021e27a 100644
--- a/cusplibrary/cusp/graph/detail/host/hilbert_curve.h
+++ b/cusplibrary/cusp/graph/detail/host/hilbert_curve.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 
 #include <cusp/exception.h>
 #include <cusp/array1d.h>
diff --git a/cusplibrary/cusp/krylov/cgls.h b/cusplibrary/cusp/krylov/cgls.h
index dd6811b..563d229 100644
--- a/cusplibrary/cusp/krylov/cgls.h
+++ b/cusplibrary/cusp/krylov/cgls.h
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 /*! \file cgls.h
  *  \brief Conjugate Gradient with Least Squares (CGLS) method
diff --git a/cusplibrary/cusp/krylov/detail/cgls.inl b/cusplibrary/cusp/krylov/detail/cgls.inl
index 2cdc8f7..c9320d6 100644
--- a/cusplibrary/cusp/krylov/detail/cgls.inl
+++ b/cusplibrary/cusp/krylov/detail/cgls.inl
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #include <cusp/array1d.h>
 #include <cusp/blas.h>
diff --git a/cusplibrary/cusp/krylov/detail/lsqr.inl b/cusplibrary/cusp/krylov/detail/lsqr.inl
index 3f5c89c..e68a320 100644
--- a/cusplibrary/cusp/krylov/detail/lsqr.inl
+++ b/cusplibrary/cusp/krylov/detail/lsqr.inl
@@ -13,6 +13,14 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
+
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #include <cusp/array1d.h>
 #include <cusp/blas.h>
 #include <cusp/multiply.h>
diff --git a/cusplibrary/cusp/krylov/lsqr.h b/cusplibrary/cusp/krylov/lsqr.h
index a45970f..d0d5166 100644
--- a/cusplibrary/cusp/krylov/lsqr.h
+++ b/cusplibrary/cusp/krylov/lsqr.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 #pragma once
 
 #include <cusp/detail/config.h>
diff --git a/cusplibrary/cusp/monitor.h b/cusplibrary/cusp/monitor.h
index c063f82..66a4418 100644
--- a/cusplibrary/cusp/monitor.h
+++ b/cusplibrary/cusp/monitor.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 /*! \file monitor.h
  *  \brief Monitor iterative solver convergence
  */
diff --git a/cusplibrary/cusp/multiply.h b/cusplibrary/cusp/multiply.h
index 45da219..d4b407d 100644
--- a/cusplibrary/cusp/multiply.h
+++ b/cusplibrary/cusp/multiply.h
@@ -14,6 +14,13 @@
  *  limitations under the License.
  */
 
+/*
+ * Modifications to this file:
+ * Copyright (c) 2014-2015, The University of Queensland
+ * Licensed under the Apache License, Version 2.0.
+ *
+ */
+
 /*! \file multiply.h
  *  \brief Matrix multiplication 
  */
diff --git a/cusplibrary/examples/Algorithms/transposed_spmv.cu b/cusplibrary/examples/Algorithms/transposed_spmv.cu
index bfd3e4e..a7add89 100644
--- a/cusplibrary/examples/Algorithms/transposed_spmv.cu
+++ b/cusplibrary/examples/Algorithms/transposed_spmv.cu
@@ -1,18 +1,19 @@
-
-/*****************************************************************************
-*
-* Copyright (c) 2014 by University of Queensland
-* http://www.uq.edu.au
-*
-* Primary Business: Queensland, Australia
-* Licensed under the Open Software License version 3.0
-* http://www.opensource.org/licenses/osl-3.0.php
-*
-* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-* Development 2012-2013 by School of Earth Sciences
-* Development from 2014 by Centre for Geoscience Computing (GeoComp)
-*
-*****************************************************************************/
+/*
+ *  Copyright 2014-2015 The University of Queensland
+ *  http://www.uq.edu.au
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
 #include <cusp/multiply.h>
 #include <cusp/cds_matrix.h>
diff --git a/debian/changelog b/debian/changelog
index dc497ee..866b560 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-escript (4.1~1-1) experimental; urgency=low
+  * Begin preparations for proper debianisation and next upstream.
+  * closes: 783157
+ -- Joel Fenwick <j.oelpublic at gmail.com>  Thu, 23 Apr 2015 17:28:21 +1000
+
+Old Changelog:
 python-escript (4.0) wheezy; urgency=low
   * Release 4.0
   * User guide has summary of changes
diff --git a/debian/changelog.trivial b/debian/changelog.trivial
new file mode 100644
index 0000000..01a5d19
--- /dev/null
+++ b/debian/changelog.trivial
@@ -0,0 +1 @@
+For information on changes between versions, see /usr/share/doc/python-escript-doc/user.pdf in the python-escript-doc package.
diff --git a/debian/control b/debian/control
index 91ce994..504d3c3 100644
--- a/debian/control
+++ b/debian/control
@@ -4,14 +4,15 @@ Priority: extra
 X-Python-Version: >=2.7
 X-Python3-Version: >=3.2
 Maintainer: Debian Science Maintainers <debian-science-maintainers at lists.alioth.debian.org>
-DM-Upload-Allowed: yes
+Uploaders:
+ Joel Fenwick <j.oelpublic at gmail.com>
 Homepage: https://launchpad.net/escript-finley
 Build-Depends: python-all-dev (>= 2.6.6-3~), python3-all-dev, python-numpy, python3-numpy,
  libboost-python-dev, libboost-random-dev, libnetcdf-dev, scons,
  zip, python-sphinx, doxygen, python-docutils, texlive, ghostscript, 
  texlive-latex-extra, latex-xcolor, lsb-release,
  libopenmpi-dev, debhelper (>=9), dh-python
-Standards-Version: 3.9.3
+Standards-Version: 3.9.6
 
 Package: python-escript
 Description: Escript/Finley finite elements python system.
@@ -22,8 +23,8 @@ Priority: extra
 Pre-Depends: dpkg (>= 1.15.6~)
 Depends: 
  ${python:Depends}, 
- python-numpy, ${es:boostpy}, ${es:boostrandom},
- ${es:netcdf}, libgomp1,
+ python-numpy, 
+ libgomp1,
  ${shlibs:Depends},
  ${misc:Depends}
 Recommends: python-sympy, python-matplotlib, python-scipy
@@ -39,7 +40,7 @@ Architecture: any
 Section: science
 Priority: extra
 Pre-Depends: dpkg (>= 1.15.6~)
-Depends: ${es:python}, python-numpy, ${es:boostpy}, ${es:boostrandom}, ${es:netcdf}, libgomp1, libopenmpi,
+Depends: ${python:Depends}, libgomp1, openmpi-bin,
  ${shlibs:Depends},
  ${misc:Depends}
 Recommends: python-sympy, python-matplotlib, python-scipy
@@ -55,7 +56,7 @@ Architecture: any
 Section: science
 Priority: extra
 Pre-Depends: dpkg (>= 1.15.6~)
-Depends: ${es:python3}, python3-numpy, ${es:boostpy3}, ${es:boostrandom3}, ${es:netcdf}, libgomp1,
+Depends: ${python:Depends}, python3-numpy, libgomp1,
  ${shlibs:Depends},
  ${misc:Depends}
 Recommends: python3-sympy, python3-matplotlib, python3-scipy
@@ -71,7 +72,7 @@ Architecture: any
 Section: science
 Priority: extra
 Pre-Depends: dpkg (>= 1.15.6~)
-Depends: ${es:python3}, python3-numpy, ${es:boostpy3}, ${es:boostrandom3}, ${es:netcdf}, libgomp1, libopenmpi,
+Depends: ${python:Depends}, python3-numpy, libgomp1, openmpi-bin,
  ${shlibs:Depends},
  ${misc:Depends}
 Recommends: python3-sympy, python3-matplotlib, python3-scipy
@@ -88,7 +89,7 @@ Architecture: all
 Section: science
 Priority: extra
 Pre-Depends: dpkg (>= 1.15.6~)
-Depends: doc-base(>=0.8.4),
+Depends: doc-base(>=0.8.4), libjs-sphinxdoc,
  ${misc:Depends}
 Recommends: python-escript
 Conflicts: escript
diff --git a/debian/copyright b/debian/copyright
index 83970ac..d0d7970 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -2,16 +2,230 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0
 Upstream-Name: esys-escript
 Source: https://launchpad.net/escript-finley
 
+License: OSL-3
+  Open Software License v. 3.0 (OSL-3.0)
+  .
+  This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+  .
+  Licensed under the Open Software License version 3.0
+  .
+  1) Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+  .
+  a) to reproduce the Original Work in copies, either alone or as part of a collective work;
+  .
+  b) to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+  .
+  c) to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License;
+  .
+  d) to perform the Original Work publicly; and
+  .
+  e) to display the Original Work publicly.
+  .
+  2) Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+  .
+  3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an inform [...]
+  .
+  4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is gr [...]
+  .
+  5) External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the [...]
+  .
+  6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+  .
+  7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY,  [...]
+  .
+  8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses.  [...]
+  .
+  9) Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in S [...]
+  .
+  10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+  .
+  11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or a [...]
+  .
+  12) Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+  .
+  13) Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+  .  
+  14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contr [...]
+  .
+  15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+  .
+  16) Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the f [...]
+
+License: ASL-2.0
+  Version 2.0, January 2004
+  .
+  http://www.apache.org/licenses/
+  .
+  TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+  .
+  1. Definitions.
+  .
+  "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+  .
+  "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+  .
+  "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+  .
+  "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+  .
+  "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+  .
+  "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+  .
+  "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+  .
+  "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+  .
+  "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or  [...]
+  .
+  "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+  .
+  2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+  .
+  3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by comb [...]
+  .
+  4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+  .
+    You must give any other recipients of the Work or Derivative Works a copy of this License; and
+    You must cause any modified files to carry prominent notices stating that You changed the files; and
+    You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+    If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; o [...]
+  .
+    You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+  .
+  5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+  .
+  6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+  .
+  7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing t [...]
+  .
+  8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not lim [...]
+  .
+  9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor [...]
+  .
+  END OF TERMS AND CONDITIONS
+
+License: Expat
+  Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+  .
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+  .
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+  .
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Files: *
+Copyright: 2003-2015 The University of Queensland
+License: OSL-3
+
 Files: debian/*
 Copyright: 2015 The University of Queensland
-License: ?????
+License: Expat
 
+#The following list was generated by a shell script
+#The numbers below correspond to:
+# 0=Copyright .* NVIDIA Corporation
+# 1=Copyright .* Steven Dalton
+# 2=Copyright .* The Regents of the University of California
+# 3=Copyright .* The University of Queensland
+# 4=Copyright, Stanford University
+# 5=Copyright (c) 1991-2004 Silicon Graphics, Inc
+#0
 Files: cusplibrary/*
-Copyright: ????
-License: Apache-2.0
-  ??? Need to have text for apache?
+Copyright: NVIDIA Corporation
+License: ASL-2.0
+
+#0 2 3
+Files: cusplibrary/cusp/complex.h
+Copyright: NVIDIA Corporation, The Regents of the University of California, The University of Queensland
+License: ASL-2.0
+
+#0 3
+Files: cusplibrary/cusp/array2d.h
+  cusplibrary/cusp/detail/multiply.inl
+  cusplibrary/cusp/detail/copy.inl
+  cusplibrary/cusp/detail/host/multiply.h
+  cusplibrary/cusp/detail/host/conversion.h
+  cusplibrary/cusp/detail/host/convert.h
+  cusplibrary/cusp/detail/dispatch/multiply.h
+  cusplibrary/cusp/detail/device/multiply.h
+  cusplibrary/cusp/detail/device/conversion.h
+  cusplibrary/cusp/detail/device/convert.h
+  cusplibrary/cusp/detail/format_utils.inl
+  cusplibrary/cusp/format.h
+  cusplibrary/cusp/multiply.h
+  cusplibrary/cusp/gallery/random.h
+  cusplibrary/cusp/graph/detail/host/hilbert_curve.h
+  cusplibrary/cusp/graph/detail/dispatch/hilbert_curve.h
+  cusplibrary/cusp/dia_matrix.h
+  cusplibrary/cusp/monitor.h
+Copyright: NVIDIA Corporation, The University of Queensland
+License: ASL-2.0
+
+#1
+Files: cusplibrary/cusp/opengl/spy/spy.h
+  cusplibrary/cusp/opengl/spy/detail/gl_util.inl
+  cusplibrary/cusp/opengl/spy/detail/glut_2d_canvas.inl
+  cusplibrary/cusp/opengl/spy/matrix_canvas.h
+  cusplibrary/cusp/opengl/spy/gl_util.h
+  cusplibrary/cusp/opengl/spy/colormaps.h
+Copyright: Steven Dalton
+License: ASL-2.0
+
+#1 4
+Files: cusplibrary/cusp/opengl/spy/detail/matrix_canvas_svg_output.inl
+  cusplibrary/cusp/opengl/spy/detail/matrix_data_cursor.inl
+  cusplibrary/cusp/opengl/spy/detail/matrix_data_panel.inl
+  cusplibrary/cusp/opengl/spy/detail/matrix_canvas.inl
+  cusplibrary/cusp/opengl/spy/matrix_data_panel.h
+  cusplibrary/cusp/opengl/spy/matrix_data_cursor.h
+Copyright: Steven Dalton, Stanford University
+License: ASL-2.0
+
+#1 5
+Files: cusplibrary/cusp/opengl/spy/glext.h
+Copyright: Steven Dalton, Silicon Graphics, Inc
+License: ASL-2.0
+
+#2
+Files: cusplibrary/cusp/krylov/detail/gmres.inl
+  cusplibrary/cusp/krylov/gmres.h
+Copyright: The Regents of the University of California
+License: ASL-2.0
+
+#2 3
+Files: cusplibrary/cusp/krylov/detail/lsqr.inl
+  cusplibrary/cusp/krylov/lsqr.h
+Copyright: The Regents of the University of California, The University of Queensland
+License: ASL-2.0
+
+#3
+Files: cusplibrary/examples/Algorithms/transposed_spmv.cu
+  cusplibrary/cusp/krylov/detail/cgls.inl
+  cusplibrary/cusp/krylov/cgls.h
+  cusplibrary/cusp/detail/cds_matrix.inl
+  cusplibrary/cusp/detail/host/spmv.h
+  cusplibrary/cusp/detail/host/transposed_multiply.h
+  cusplibrary/cusp/detail/host/transposed_spmv.h
+  cusplibrary/cusp/detail/device/spmv/cds.h
+  cusplibrary/cusp/detail/device/spmv/cds_symmetric.h
+  cusplibrary/cusp/detail/device/transposed_multiply.h
+  cusplibrary/cusp/detail/device/transposed_spmv/cds.h
+  cusplibrary/cusp/detail/device/transposed_spmv/dia.h
+  cusplibrary/cusp/cds_matrix.h
+Copyright: The University of Queensland
+License: ASL-2.0
 
-Files: *
-Copyright: 2003-2015 The University of Queensland
-License: Open Software License version 3.0
-  ??? Need to add the actual text of the license
\ No newline at end of file
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..e69de29
diff --git a/debian/python-escript-doc.dirs b/debian/python-escript-doc.dirs
new file mode 100644
index 0000000..dc6ae1b
--- /dev/null
+++ b/debian/python-escript-doc.dirs
@@ -0,0 +1 @@
+usr/share/doc/python-escript-doc
diff --git a/debian/python-escript-doc.examples b/debian/python-escript-doc.examples
new file mode 100644
index 0000000..2b75355
--- /dev/null
+++ b/debian/python-escript-doc.examples
@@ -0,0 +1 @@
+debian/stage2/release/doc/escript_examples.tar.gz
diff --git a/debian/python-escript-doc.install b/debian/python-escript-doc.install
new file mode 100644
index 0000000..fd8c467
--- /dev/null
+++ b/debian/python-escript-doc.install
@@ -0,0 +1,7 @@
+debian/stage2/release/doc/install/install.pdf	usr/share/doc/python-escript-doc
+debian/stage2/release/doc/user/user.pdf		usr/share/doc/python-escript-doc
+debian/stage2/release/doc/cookbook/cookbook.pdf	usr/share/doc/python-escript-doc
+debian/stage2/release/doc/inversion/inversion.pdf	usr/share/doc/python-escript-doc/
+debian/stage2/release/doc/sphinx_api 		usr/share/doc/python-escript-doc/python_html
+debian/stage2/release/doc/doxygen 		usr/share/doc/python-escript-doc/doxygen
+debian/copyright	usr/share/doc/python-escript-doc
diff --git a/debian/python-escript-doc.links b/debian/python-escript-doc.links
new file mode 100644
index 0000000..d97940c
--- /dev/null
+++ b/debian/python-escript-doc.links
@@ -0,0 +1,19 @@
+/usr/share/sphinx/themes/basic/static/ajax-loader.gif	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/ajax-loader.gif
+/usr/share/javascript/sphinxdoc/1.0/basic.css 		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/basic.css
+/usr/share/sphinx/themes/basic/static/comment-bright.png usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/comment-bright.png
+/usr/share/sphinx/themes/basic/static/comment-close.png usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/comment-close.png
+/usr/share/sphinx/themes/basic/static/comment.png	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/comment.png
+/usr/share/sphinx/themes/basic/static/doctools.js	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/doctools.js
+/usr/share/sphinx/themes/basic/static/down.png		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/down.png
+/usr/share/sphinx/themes/basic/static/down-pressed.png	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/down-pressed.png
+/usr/share/sphinx/themes/basic/static/file.png		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/file.png
+/usr/share/sphinx/themes/basic/static/jquery.js		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/jquery.js
+/usr/share/sphinx/themes/basic/static/minus.png		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/minus.png
+/usr/share/sphinx/themes/basic/static/plus.png		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/plus.png
+/usr/share/javascript/sphinxdoc/1.0/searchtools.js	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/searchtools.js
+/usr/share/javascript/sphinxdoc/1.0/sidebar.js		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/sidebar.js
+/usr/share/sphinx/themes/basic/static/underscore.js	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/underscore.js
+/usr/share/sphinx/themes/basic/static/up.png		usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/up.png
+/usr/share/sphinx/themes/basic/static/up-pressed.png	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/up-pressed.png
+/usr/share/sphinx/themes/basic/static/websupport.js	usr/share/doc/python-escript-doc/python_html/sphinx_api/_static/websupport.js
+
diff --git a/debian/python-escript-doc.lintian-overrides b/debian/python-escript-doc.lintian-overrides
new file mode 100644
index 0000000..d17ac03
--- /dev/null
+++ b/debian/python-escript-doc.lintian-overrides
@@ -0,0 +1,3 @@
+
+# science packages belong in the science section according to science policy
+python-escript-doc: wrong-section-according-to-package-name
diff --git a/debian/python-escript-mpi.dirs b/debian/python-escript-mpi.dirs
new file mode 100644
index 0000000..8e5a8d6
--- /dev/null
+++ b/debian/python-escript-mpi.dirs
@@ -0,0 +1,4 @@
+usr/share/doc/python-escript-mpi/
+usr/share/man/man1
+usr/lib/python-escript-mpi
+usr/bin
diff --git a/debian/python-escript-mpi.install b/debian/python-escript-mpi.install
new file mode 100644
index 0000000..02b9574
--- /dev/null
+++ b/debian/python-escript-mpi.install
@@ -0,0 +1,5 @@
+debian/stage2M/lib/* usr/lib/python-escript-mpi/lib
+debian/stage2M/bin/escript-overlord usr/lib/python-escript-mpi
+debian/stage2M/esys  usr/lib/python-escript-mpi
+debian/stage2M/bin/run-escript2-mpi usr/bin
+debian/copyright	usr/share/doc/python-escript-mpi
diff --git a/debian/python-escript-mpi.lintian-overrides b/debian/python-escript-mpi.lintian-overrides
new file mode 100644
index 0000000..648b7ca
--- /dev/null
+++ b/debian/python-escript-mpi.lintian-overrides
@@ -0,0 +1,6 @@
+
+# All libraries are build with the same flags, only some are reported
+# as being un-hardened.
+python-escript-mpi: hardening-no-fortify-functions
+
+python-escript-mpi: wrong-section-according-to-package-name
diff --git a/debian/python-escript-mpi.manpages b/debian/python-escript-mpi.manpages
new file mode 100644
index 0000000..3dc1755
--- /dev/null
+++ b/debian/python-escript-mpi.manpages
@@ -0,0 +1 @@
+debian/stage2M/run-escript2-mpi.man
diff --git a/debian/python-escript-mpi.postinst b/debian/python-escript-mpi.postinst
index 7cab9b9..53ceec3 100644
--- a/debian/python-escript-mpi.postinst
+++ b/debian/python-escript-mpi.postinst
@@ -3,11 +3,11 @@ set -e
 
 case "$1" in
     configure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2-mpi 60
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2-mpi 30
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2-mpi 60
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2-mpi 30
     ;;
 
     *)
diff --git a/debian/python-escript-mpi.prerm b/debian/python-escript-mpi.prerm
index b7c5948..b947289 100644
--- a/debian/python-escript-mpi.prerm
+++ b/debian/python-escript-mpi.prerm
@@ -3,7 +3,7 @@ set -e
 
 case "$1" in
     remove|upgrade|deconfigure)
-      update-alternatives --remove run-escript /usr/bin/run-escript3-mpi
+      update-alternatives --remove run-escript /usr/bin/run-escript2-mpi
     ;;
 
     failed-upgrade)
diff --git a/debian/python-escript.dirs b/debian/python-escript.dirs
new file mode 100644
index 0000000..b575398
--- /dev/null
+++ b/debian/python-escript.dirs
@@ -0,0 +1,4 @@
+usr/share/doc/python-escript/
+usr/share/man/man1
+usr/lib/python-escript
+usr/bin
diff --git a/debian/python-escript.install b/debian/python-escript.install
new file mode 100644
index 0000000..bd89752
--- /dev/null
+++ b/debian/python-escript.install
@@ -0,0 +1,4 @@
+debian/stage2/lib/* usr/lib/python-escript/lib
+debian/stage2/esys  usr/lib/python-escript
+debian/stage2/bin/run-escript2 usr/bin
+debian/copyright	usr/share/doc/python-escript
diff --git a/debian/python-escript.lintian-overrides b/debian/python-escript.lintian-overrides
new file mode 100644
index 0000000..aeb68d0
--- /dev/null
+++ b/debian/python-escript.lintian-overrides
@@ -0,0 +1,7 @@
+
+# science packages belong in the science section according to science policy
+python-escript: wrong-section-according-to-package-name
+
+# All libraries are build with the same flags, only some are reported
+# as being un-hardened.
+python-escript: hardening-no-fortify-functions
diff --git a/debian/python-escript.manpages b/debian/python-escript.manpages
new file mode 100644
index 0000000..986efca
--- /dev/null
+++ b/debian/python-escript.manpages
@@ -0,0 +1 @@
+debian/stage2/run-escript2.man
diff --git a/debian/python-escript.postinst b/debian/python-escript.postinst
index 97db549..d9433bb 100644
--- a/debian/python-escript.postinst
+++ b/debian/python-escript.postinst
@@ -3,11 +3,11 @@ set -e
 
 case "$1" in
     configure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2 40
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2 50
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2 40
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript2 50
     ;;
 
     *)
diff --git a/debian/python-escript.prerm b/debian/python-escript.prerm
index d0a0d07..5de3513 100644
--- a/debian/python-escript.prerm
+++ b/debian/python-escript.prerm
@@ -3,7 +3,7 @@ set -e
 
 case "$1" in
     remove|upgrade|deconfigure)
-      update-alternatives --remove run-escript /usr/bin/run-escript3
+      update-alternatives --remove run-escript /usr/bin/run-escript2
     ;;
 
     failed-upgrade)
diff --git a/debian/python3-escript-mpi.dirs b/debian/python3-escript-mpi.dirs
new file mode 100644
index 0000000..0dba876
--- /dev/null
+++ b/debian/python3-escript-mpi.dirs
@@ -0,0 +1,4 @@
+usr/share/doc/python3-escript-mpi/
+usr/share/man/man1
+usr/lib/python3-escript-mpi
+usr/bin
diff --git a/debian/python3-escript-mpi.install b/debian/python3-escript-mpi.install
new file mode 100644
index 0000000..ac6ffd1
--- /dev/null
+++ b/debian/python3-escript-mpi.install
@@ -0,0 +1,5 @@
+debian/stage3M/lib/* usr/lib/python3-escript-mpi/lib
+debian/stage3M/bin/escript-overlord usr/lib/python3-escript-mpi
+debian/stage3M/esys  usr/lib/python3-escript-mpi
+debian/stage3M/bin/run-escript3-mpi usr/bin
+debian/copyright	usr/share/doc/python3-escript-mpi
diff --git a/debian/python3-escript-mpi.lintian-overrides b/debian/python3-escript-mpi.lintian-overrides
new file mode 100644
index 0000000..9ff3821
--- /dev/null
+++ b/debian/python3-escript-mpi.lintian-overrides
@@ -0,0 +1,5 @@
+
+# All libraries are build with the same flags, only some are reported
+# as being un-hardened.
+python3-escript-mpi: hardening-no-fortify-functions
+
diff --git a/debian/python3-escript-mpi.manpages b/debian/python3-escript-mpi.manpages
new file mode 100644
index 0000000..d5c5cb1
--- /dev/null
+++ b/debian/python3-escript-mpi.manpages
@@ -0,0 +1 @@
+debian/stage3M/run-escript3-mpi.man
diff --git a/debian/python-escript3-mpi.postinst b/debian/python3-escript-mpi.postinst
similarity index 84%
rename from debian/python-escript3-mpi.postinst
rename to debian/python3-escript-mpi.postinst
index c9f1cfa..3aa134f 100644
--- a/debian/python-escript3-mpi.postinst
+++ b/debian/python3-escript-mpi.postinst
@@ -3,11 +3,11 @@ set -e
 
 case "$1" in
     configure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3-mpi 50
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3-mpi 20
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3-mpi 50
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3-mpi 20
     ;;
 
     *)
diff --git a/debian/python-escript3-mpi.prerm b/debian/python3-escript-mpi.prerm
similarity index 100%
rename from debian/python-escript3-mpi.prerm
rename to debian/python3-escript-mpi.prerm
diff --git a/debian/python3-escript.dirs b/debian/python3-escript.dirs
new file mode 100644
index 0000000..f2b3b8b
--- /dev/null
+++ b/debian/python3-escript.dirs
@@ -0,0 +1,4 @@
+usr/share/doc/python3-escript/
+usr/share/man/man1
+usr/lib/python3-escript
+usr/bin
diff --git a/debian/python3-escript.install b/debian/python3-escript.install
new file mode 100644
index 0000000..e5315ea
--- /dev/null
+++ b/debian/python3-escript.install
@@ -0,0 +1,4 @@
+debian/stage3/lib/* usr/lib/python3-escript/lib
+debian/stage3/esys  usr/lib/python3-escript
+debian/stage3/bin/run-escript3 usr/bin
+debian/copyright	usr/share/doc/python3-escript
diff --git a/debian/python3-escript.lintian-overrides b/debian/python3-escript.lintian-overrides
new file mode 100644
index 0000000..d17f3e7
--- /dev/null
+++ b/debian/python3-escript.lintian-overrides
@@ -0,0 +1,5 @@
+
+# All libraries are build with the same flags, only some are reported
+# as being un-hardened.
+python3-escript: hardening-no-fortify-functions
+
diff --git a/debian/python3-escript.manpages b/debian/python3-escript.manpages
new file mode 100644
index 0000000..99ddf1c
--- /dev/null
+++ b/debian/python3-escript.manpages
@@ -0,0 +1 @@
+debian/stage3/run-escript3.man
diff --git a/debian/python-escript3.postinst b/debian/python3-escript.postinst
similarity index 85%
rename from debian/python-escript3.postinst
rename to debian/python3-escript.postinst
index 8429a35..e646498 100644
--- a/debian/python-escript3.postinst
+++ b/debian/python3-escript.postinst
@@ -3,11 +3,11 @@ set -e
 
 case "$1" in
     configure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3 20
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3 40
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)
-      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3 20
+      update-alternatives --install /usr/bin/run-escript run-escript /usr/bin/run-escript3 40
     ;;
 
     *)
diff --git a/debian/python-escript3.prerm b/debian/python3-escript.prerm
similarity index 100%
rename from debian/python-escript3.prerm
rename to debian/python3-escript.prerm
diff --git a/debian/rules b/debian/rules
index 9a6ed8c..8a29ac9 100755
--- a/debian/rules
+++ b/debian/rules
@@ -10,8 +10,8 @@ BUILD=$(CURDIR)/debian/tmp2
 BUILDM=$(CURDIR)/debian/tmp2M
 BUILD3=$(CURDIR)/debian/tmp3
 BUILD3M=$(CURDIR)/debian/tmp3M
-WORK=$(CURDIR)/debian/stage
-WORKM=$(CURDIR)/debian/stageM
+WORK=$(CURDIR)/debian/stage2
+WORKM=$(CURDIR)/debian/stage2M
 WORK3=$(CURDIR)/debian/stage3
 WORK3M=$(CURDIR)/debian/stage3M
 
@@ -24,7 +24,7 @@ ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
     parbuild=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
     sflags=-j$(parbuild)
 else
-    sflags=-j12
+    sflags=-j10
 endif
 
 
@@ -45,6 +45,7 @@ clean:
 	rm -rf $(WORK3M)
 	rm -rf $(CURDIR)/debian/tmp/*
 	rm -f debian/files
+	rm -f debian/substvars
 	dh_clean
 
 build: build-arch build-indep
@@ -52,22 +53,38 @@ build: build-arch build-indep
 build-arch: build2 build2M build3 build3M
 
 # build2 will be the compiled version we extract doco from
-build-indep: build2	
+# be careful that the scons call in here does not overwrite changes made in build2:
+build-indep: build2
+	mkdir -p $(BUILD)
 	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILD) verbose=on prefix=$(WORK) options_file=`debian/utils/getsubst`_options.py docs
+	find $(WORK) -name '*.pyc' -print0 | xargs -0 rm -f
+	# remove MathJax includes
+	sed -i -e 's%<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>%%' $(WORK)/release/doc/sphinx_api/*.html
 
 build2:	
 	mkdir -p $(WORK)
 	if [ ! -f svn_version ];then echo "No svn_version file found"; exit 3;fi
 	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILD) verbose=on prefix=$(WORK) options_file=`debian/utils/getsubst`_options.py
 	sed -i -e "s%STDLOCATION=0%STDLOCATION=1%" $(WORK)/bin/run-escript
+	# extract the relevant .py files
+	cd $(WORK); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
+	cp $(PROJROOT)/doc/manpage/man1/run-escript.1 $(WORK)/run-escript2.man
+	mv $(WORK)/bin/run-escript $(WORK)/bin/run-escript2
+	find $(WORK) -name '*.pyc' -print0 | xargs -0 rm -f
 
 build2M:
 	mkdir -p $(WORKM)
 	if [ ! -f svn_version ];then echo "No svn_version file found"; exit 3;fi
-	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILDM) verbose=on prefix=$(WORKM) options_file=`debian/utils/getsubst`_mpi_options.py
+	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILDM)  cpp_extra='-DOVERLORDPATH=\"/usr/lib/python-escript-mpi/\"' verbose=on prefix=$(WORKM) options_file=`debian/utils/getsubst`_mpi_options.py
 	sed -i -e "s%ESCRIPT_ROOT=/usr/lib/python-escript%ESCRIPT_ROOT=/usr/lib/python-escript-mpi%" $(WORKM)/bin/run-escript
 	sed -i -e "s%STDLOCATION=0%STDLOCATION=1%" $(WORKM)/bin/run-escript
-
+	# extract the relevant .py files
+	cd $(WORKM); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
+	cp $(PROJROOT)/doc/manpage/man1/run-escript.1 $(WORKM)/run-escript2-mpi.man
+	ln $(WORKM)/bin/run-escript $(WORKM)/bin/run-escript2-mpi
+	find $(WORKM) -name '*.pyc' -print0| xargs -0 rm -f
+	rm -rf $(BUILDM)
+	
 build3:	
 	mkdir -p $(WORK3)
 	if [ ! -f svn_version ];then echo "No svn_version file found"; exit 3;fi
@@ -75,14 +92,26 @@ build3:
 	sed -i -e "s%STDLOCATION=0%STDLOCATION=1%" $(WORK3)/bin/run-escript
 	sed -i -e "s%ESCRIPT_ROOT=/usr/lib/python-escript%ESCRIPT_ROOT=/usr/lib/python3-escript%" $(WORK3)/bin/run-escript
 	sed -i -e "s%PYTHON_CMD=python%PYTHON_CMD=python3%" $(WORK3)/bin/run-escript
+	# extract the relevant .py files
+	cd $(WORK3); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
+	cp $(PROJROOT)/doc/manpage/man1/run-escript.1 $(WORK3)/run-escript3.man
+	ln $(WORK3)/bin/run-escript $(WORK3)/bin/run-escript3
+	find $(WORK3) -name '*.pyc' -print0| xargs -0 rm -f
+	rm -rf $(BUILD3)
 
 build3M:
 	mkdir -p $(WORK3M)
 	if [ ! -f svn_version ];then echo "No svn_version file found"; exit 3;fi
-	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILD3M) verbose=on prefix=$(WORK3M) options_file=`debian/utils/getsubst`_py3_mpi_options.py
+	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILD3M)  cpp_extra='-DOVERLORDPATH=\"/usr/lib/python-escript3-mpi/\"' verbose=on prefix=$(WORK3M) options_file=`debian/utils/getsubst`_py3_mpi_options.py
 	sed -i -e "s%ESCRIPT_ROOT=/usr/lib/python-escript%ESCRIPT_ROOT=/usr/lib/python3-escript-mpi%" $(WORK3M)/bin/run-escript
 	sed -i -e "s%STDLOCATION=0%STDLOCATION=1%" $(WORK3M)/bin/run-escript
 	sed -i -e "s%PYTHON_CMD=python%PYTHON_CMD=python3%" $(WORK3M)/bin/run-escript
+	# extract the relevant .py files
+	cd $(WORK3M); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
+	cp $(PROJROOT)/doc/manpage/man1/run-escript.1 $(WORK3M)/run-escript3-mpi.man
+	ln $(WORK3M)/bin/run-escript $(WORK3M)/bin/run-escript3-mpi
+	find $(WORK3M) -name '*.pyc' -print0| xargs -0 rm -f	
+	rm -rf $(BUILD3M)
 
 
 binary: binary-arch binary-indep
@@ -90,142 +119,114 @@ binary: binary-arch binary-indep
 binary-arch: binary-arch2 binary-arch2M binary-arch3 binary-arch3M
 
 binary-arch2:
-	mkdir -p $(BDEST)/usr/share/doc/python-escript/
-	mkdir -p $(BDEST)/usr/share/man/man1
-	mkdir -p $(BDEST)/usr/lib/python-escript
-	mkdir -p $(BDEST)/usr/bin
-	cd $(WORK); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
-	cp $(WORK)/lib/* $(BDEST)/usr/lib/python-escript
-	cp -r $(WORK)/esys $(BDEST)/usr/lib/python-escript
-	cp $(WORK)/bin/run-escript $(BDEST)/usr/bin/run-escript2
-	cp doc/manpage/man1/run-escript.1 $(BDEST)/usr/share/man/man1/run-escript2.1
-	gzip -f9 $(BDEST)/usr/share/man/man1/run-escript2.1
-	install --mode=644 debian/changelog $(BDEST)/usr/share/doc/python-escript/changelog.Debian
-	gzip -f9 $(BDEST)/usr/share/doc/python-escript/changelog.Debian
-	install --mode=644 debian/copyright $(BDEST)/usr/share/doc/python-escript
-	mkdir -p debian/python-escript/DEBIAN
-	find debian/python-escript -name '*.pyc' | xargs rm -f
-	find $(BDEST) -name '*.so' | xargs strip
-	dh_lintian -P$(BDEST) -ppython-escript
-	dh_makeshlibs -P$(BDEST) -ppython-escript
-	dh_shlibdeps -P$(BDEST) -ppython-escript
-	dpkg-gencontrol -P$(BDEST) -ppython-escript
-	install --mode=755 debian/python-escript.postinst $(BDEST)/DEBIAN/postinst
-	dh_python2 -p python-escript  --no-ext-rename
-	install --mode=755 debian/python-escript.prerm $(BDEST)/DEBIAN/prerm
-	#Thanks to Krafft's book for this
-	cd debian/python-escript && find * -path DEBIAN -prune -o -type f -print | xargs md5sum > DEBIAN/md5sums
-	dpkg-deb --build debian/python-escript ..
-
-
+	dh_testroot   
+	dh_prep			-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_testdir
+	dh_installdirs		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_install		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_installchangelogs	-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST) debian/changelog.trivial	
+	dh_installman		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_python2 --compile-all -ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc --no-ext-rename usr/lib/python-escript/esys
+	dh_lintian		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_compress		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_fixperms		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_strip			-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_makeshlibs		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)
+	dh_shlibdeps		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	 -l$(BDEST)/usr/lib/python-escript	
+	dh_installdeb		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_gencontrol		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)
+	#This should not be necessary
+	sed -i -e 's/#PACKAGE#/python-escript/' debian/python-escript/DEBIAN/prerm
+	sed -i -e 's/pyclean [^>]/pyclean -p python-escript /' debian/python-escript/DEBIAN/prerm	
+	dh_md5sums		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	dh_builddeb		-ppython-escript -Npython3-escript -Npython-escript-mpi -Npython3-escript-mpi  -Npython-escript-doc -P$(BDEST)	
+	
 binary-arch2M:
-	mkdir -p $(BMDEST)/usr/share/doc/python-escript-mpi/
-	mkdir -p $(BMDEST)/usr/share/man/man1
-	mkdir -p $(BMDEST)/usr/lib/python-escript-mpi
-	mkdir -p $(BMDEST)/usr/bin
-	cd $(WORKM); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
-	strip $(WORKM)/lib/pythonMPI $(WORKM)/lib/pythonMPIredirect
-	cp $(WORKM)/lib/pythonMPI $(WORKM)/lib/pythonMPI $(BMDEST)/usr/lib/python-escript-mpi
-	cp $(WORKM)/lib/* $(BMDEST)/usr/lib/python-escript-mpi
-	cp -r $(WORKM)/esys $(BMDEST)/usr/lib/python-escript-mpi
-	cp $(WORKM)/bin/run-escript $(BMDEST)/usr/bin/run-escript2-mpi
-	cp doc/manpage/man1/run-escript.1 $(BMDEST)/usr/share/man/man1/run-escript2-mpi.1
-	gzip -f9 $(BMDEST)/usr/share/man/man1/run-escript2-mpi.1
-	install --mode=644 debian/changelog $(BMDEST)/usr/share/doc/python-escript-mpi/changelog.Debian
-	gzip -f9 $(BMDEST)/usr/share/doc/python-escript-mpi/changelog.Debian
-	install --mode=644 debian/copyright $(BMDEST)/usr/share/doc/python-escript-mpi
-	mkdir -p debian/python-escript-mpi/DEBIAN
-	find debian/python-escript-mpi -name '*.pyc' | xargs rm -f
-	find $(BMDEST) -name '*.so' | xargs strip
-	dh_lintian -P$(BMDEST) -ppython-escript-mpi
-	dh_makeshlibs -P$(BMDEST) -ppython-escript-mpi
-	dh_shlibdeps -P$(BMDEST) -ppython-escript-mpi
-	dpkg-gencontrol -P$(BMDEST) -ppython-escript-mpi
-	install --mode=755 debian/python-escript-mpi.postinst $(BMDEST)/DEBIAN/postinst
-	dh_python2 -p python-escript-mpi  --no-ext-rename
-	install --mode=755 debian/python-escript-mpi.prerm $(BMDEST)/DEBIAN/prerm
-	#Thanks to Krafft's book for this
-	cd debian/python-escript-mpi && find * -path DEBIAN -prune -o -type f -print | xargs md5sum > DEBIAN/md5sums
-	dpkg-deb --build debian/python-escript-mpi ..
+	dh_testroot   
+	dh_prep		-ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_testdir
+	dh_installdirs -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_install -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_installchangelogs -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST) debian/changelog.trivial
+	dh_installman -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	# dh_python2 does not have a -P param. Need to do some experiments to ensure it is dealing with correct dir
+	dh_python2 --compile-all -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc --no-ext-rename	usr/lib/python-escript-mpi/esys
+	dh_lintian -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_compress -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_fixperms -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_strip		-ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_makeshlibs	-ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_shlibdeps	-ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST) -l$(BMDEST)/usr/lib/python-escript-mpi
+	dh_installdeb -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_gencontrol -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	#This should not be necessary
+	sed -i -e 's/#PACKAGE#/python-escript-mpi/' debian/python-escript-mpi/DEBIAN/prerm
+	sed -i -e 's/pyclean [^>]/pyclean -p python-escript-mpi /' debian/python-escript-mpi/DEBIAN/prerm	
+	dh_md5sums -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
+	dh_builddeb -ppython-escript-mpi -Npython3-escript -Npython-escript -Npython3-escript-mpi -Npython-escript-doc -P$(BMDEST)
 
 binary-arch3:
-	mkdir -p $(B3DEST)/usr/share/doc/python3-escript/
-	mkdir -p $(B3DEST)/usr/share/man/man1
-	mkdir -p $(B3DEST)/usr/lib/python3-escript
-	mkdir -p $(B3DEST)/usr/bin
-	cd $(WORK3); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
-	cp $(WORK3)/lib/* $(B3DEST)/usr/lib/python3-escript
-	cp -r $(WORK3)/esys $(B3DEST)/usr/lib/python3-escript
-	cp $(WORK3)/bin/run-escript $(B3DEST)/usr/bin/run-escript3
-	cp doc/manpage/man1/run-escript.1 $(B3DEST)/usr/share/man/man1/run-escript3.1
-	gzip -9 $(B3DEST)/usr/share/man/man1/run-escript3.1
-	install --mode=644 debian/changelog $(B3DEST)/usr/share/doc/python3-escript/changelog.Debian
-	gzip -f9 $(B3DEST)/usr/share/doc/python3-escript/changelog.Debian
-	install --mode=644 debian/copyright $(B3DEST)/usr/share/doc/python3-escript
-	mkdir -p debian/python3-escript/DEBIAN 
-	find debian/python3-escript -name '*.pyc' | xargs rm -f
-	find $(B3DEST) -name '*.so' | xargs strip
-	dh_lintian -P$(B3DEST) -ppython3-escript
-	dh_makeshlibs -P$(B3DEST) -ppython3-escript
-	dh_shlibdeps -P$(B3DEST) -ppython3-escript
-	dpkg-gencontrol -P$(B3DEST) -ppython3-escript
-	install --mode=755 debian/python-escript3.postinst $(B3DEST)/DEBIAN/postinst
-	dh_python3 -p python3-escript  --no-ext-rename
-	install --mode=755 debian/python-escript3.prerm $(B3DEST)/DEBIAN/prerm
-	#Thanks to Krafft's book for this
-	cd debian/python3-escript && find * -path DEBIAN -prune -o -type f -print | xargs md5sum > DEBIAN/md5sums
-	dpkg-deb --build debian/python3-escript ..
+	dh_testroot   
+	dh_prep			-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)	
+	dh_testdir
+	dh_installdirs 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_install 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_installchangelogs 	-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)	 debian/changelog.trivial
+	dh_installman 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	# dh_python2 does not have a -P param. Need to do some experiments to ensure it is dealing with correct dir
+	dh_python3 		--compile-all -ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc --no-ext-rename	usr/lib/python3-escript/esys
+	dh_lintian 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_compress 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_fixperms 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_strip			-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_makeshlibs		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_shlibdeps		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST) -l$(B3DEST)/usr/lib/python3-escript
+	dh_installdeb 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	dh_gencontrol  		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
+	#This should not be necessary
+	sed -i -e 's/#PACKAGE#/python3-escript/' debian/python3-escript/DEBIAN/prerm	
+	sed -i -e 's/py3clean [^>]/py3clean -p python3-escript /' debian/python3-escript/DEBIAN/prerm	
+	dh_md5sums 		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST) 
+	dh_builddeb		-ppython3-escript -Npython-escript -Npython-escript-mpi -Npython3-escript-mpi -Npython-escript-doc -P$(B3DEST)
 
 binary-arch3M:
-	mkdir -p $(B3MDEST)/usr/share/doc/python3-escript-mpi/
-	mkdir -p $(B3MDEST)/usr/share/man/man1
-	mkdir -p $(B3MDEST)/usr/lib/python3-escript-mpi
-	mkdir -p $(B3MDEST)/usr/bin
-	cd $(WORK3M); $(PROJROOT)/debian/utils/cppy.py $(PROJROOT); cd $(PROJROOT)
-	cp $(WORK3M)/lib/* $(B3MDEST)/usr/lib/python3-escript-mpi
-	cp -r $(WORK3M)/esys $(B3MDEST)/usr/lib/python3-escript-mpi
-	cp $(WORK3M)/bin/run-escript $(B3MDEST)/usr/bin/run-escript3-mpi
-	strip $(WORK3M)/lib/pythonMPI $(WORK3M)/lib/pythonMPIredirect
-	cp $(WORK3M)/lib/pythonMPI $(WORK3M)/lib/pythonMPI $(B3MDEST)/usr/lib/python3-escript-mpi
-	cp doc/manpage/man1/run-escript.1 $(B3MDEST)/usr/share/man/man1/run-escript3-mpi.1
-	gzip -f9 $(B3MDEST)/usr/share/man/man1/run-escript3-mpi.1
-	install --mode=644 debian/changelog $(B3MDEST)/usr/share/doc/python3-escript-mpi/changelog.Debian
-	gzip -f9 $(B3MDEST)/usr/share/doc/python3-escript-mpi/changelog.Debian
-	install --mode=644 debian/copyright $(B3MDEST)/usr/share/doc/python3-escript-mpi
-	mkdir -p $(B3MDEST)/DEBIAN 
-	find $(B3MDEST) -name '*.pyc' | xargs rm -f
-	find $(B3MDEST) -name '*.so' | xargs strip
-	dh_lintian -P$(B3MDEST) -ppython3-escript-mpi
-	dh_makeshlibs -P$(B3MDEST) -ppython3-escript-mpi
-	dh_shlibdeps -P$(B3MDEST) -ppython3-escript-mpi
-	dh_strip -P$(B3MDEST) -ppython3-escript-mpi
-	dpkg-gencontrol -P$(B3MDEST) -ppython3-escript-mpi
-	install --mode=755 debian/python-escript3-mpi.postinst $(B3MDEST)/DEBIAN/postinst
-	dh_python3 -p python3-escript-mpi  --no-ext-rename
-	install --mode=755 debian/python-escript3-mpi.prerm $(B3MDEST)/DEBIAN/prerm
-	#Thanks to Krafft's book for this
-	cd debian/python3-escript-mpi && find * -path DEBIAN -prune -o -type f -print | xargs md5sum > DEBIAN/md5sums
-	dpkg-deb --build debian/python3-escript-mpi ..
-
+	dh_testroot   
+	dh_prep			-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_testdir
+	dh_installdirs		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_install		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_installchangelogs 	-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)	 debian/changelog.trivial
+	dh_installman 		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	# dh_python2 does not have a -P param. Need to do some experiments to ensure it is dealing with correct dir
+	dh_python3		--compile-all -ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc --no-ext-rename	usr/lib/python3-escript-mpi/esys
+	dh_lintian 		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_compress		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_fixperms		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_strip			-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_makeshlibs		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_shlibdeps		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST) -l$(B3MDEST)/usr/lib/python3-escript-mpi
+	dh_installdeb		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	dh_gencontrol		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
+	#This should not be necessary
+	sed -i -e 's/#PACKAGE#/python3-escript-mpi/' debian/python3-escript-mpi/DEBIAN/prerm
+	sed -i -e 's/py3clean [^>]/py3clean -p python3-escript-mpi /' debian/python3-escript-mpi/DEBIAN/prerm		
+	dh_md5sums		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST) 
+	dh_builddeb		-ppython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -Npython-escript-doc -P$(B3MDEST)
 
 binary-indep:
-	mkdir -p $(DDEST)
-	mkdir -p $(DDEST)/usr/share/doc/python-escript-doc/
-	mkdir -p debian/python-escript-doc/DEBIAN
-	scons $(sflags) SVN_VERSION=`cat svn_version` build_dir=$(BUILD) verbose=on prefix=$(WORK) options_file=`debian/utils/getsubst`_options.py docs
-	install --mode=644 debian/copyright $(DDEST)/usr/share/doc/python-escript-doc
-	install --mode=644 debian/changelog $(DDEST)/usr/share/doc/python-escript-doc/changelog.Debian
-	gzip -f9 $(DDEST)/usr/share/doc/python-escript-doc/changelog.Debian
-	cp $(WORK)/release/doc/escript_examples.tar.gz $(DDEST)/usr/share/doc/python-escript-doc/
-	cp $(WORK)/release/doc/install/install.pdf $(DDEST)/usr/share/doc/python-escript-doc
-	cp $(WORK)/release/doc/user/user.pdf $(DDEST)/usr/share/doc/python-escript-doc
-	cp $(WORK)/release/doc/cookbook/cookbook.pdf $(DDEST)/usr/share/doc/python-escript-doc
-	cp $(WORK)/release/doc/inversion/inversion.pdf $(DDEST)/usr/share/doc/python-escript-doc/
-	cp -r $(WORK)/release/doc/sphinx_api $(DDEST)/usr/share/doc/python-escript-doc/python_html
-	cp -r $(WORK)/release/doc/doxygen $(DDEST)/usr/share/doc/python-escript-doc/doxygen	
-	cd $(DDEST) && find * -path DEBIAN -prune -o -type f -print | xargs md5sum > DEBIAN/md5sums
-	dh_lintian -P$(DDEST) -ppython-escript-doc
-	dpkg-gencontrol -P$(DDEST) -ppython-escript-doc
-	dh_fixperms -P$(DDEST) -ppython-escript-doc
-	dpkg-deb --build debian/python-escript-doc ..
-
+	dh_testroot
+	dh_prep			-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_testdir
+	dh_installdirs		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_install 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_installchangelogs	-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST) debian/changelog.trivial
+	dh_installexamples	-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_link -ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_lintian 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_compress 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_fixperms 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_strip			-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_installdeb 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_gencontrol 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_md5sums		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
+	dh_builddeb 		-ppython-escript-doc -Npython3-escript-mpi -Npython3-escript -Npython-escript -Npython-escript-mpi -P$(DDEST)
diff --git a/debian/source/format b/debian/source/format
index 89ae9db..163aaf8 100644
--- a/debian/source/format
+++ b/debian/source/format
@@ -1 +1 @@
-3.0 (native)
+3.0 (quilt)
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
deleted file mode 100644
index 66edfbb..0000000
--- a/debian/source/lintian-overrides
+++ /dev/null
@@ -1,7 +0,0 @@
-
-# science packages belong in the science section according to science policy
-#python-escript-doc: wrong-section-according-to-package-name
-#python-escript-mpi: wrong-section-according-to-package-name
-#python-escript: wrong-section-according-to-package-name
-
-python-escript: wrong-section-according-to-package-name python-escript
diff --git a/debprep.notes b/debprep.notes
deleted file mode 100644
index 268ebce..0000000
--- a/debprep.notes
+++ /dev/null
@@ -1,36 +0,0 @@
-Separate packages for py3/p2/mpi/non-mpi
-virtual packages for escriptMPI  escript-nonMPI
-
- -- still to do
-
-lintian --- already installed
-  Lots of things are broken. 
-  - man page was not compressed  -- should be fixed
-  - python files should not be precompiled  --- need to look at policy for how that should be done
-    * Not certain if all deps (especially optional ones) are at py3 yet.  On that basis:
-      https://www.debian.org/doc/packaging-manuals/python-policy/ch-python3.html
-      we should package both py2 and py3
-    * from https://www.debian.org/doc/packaging-manuals/python-policy/ch-python.html
-      2.5 talks about the module path and "Public Python modules".   
-      I'm leaning towards our modules not being public because you should be using the launcher (or know enough to do it yourself.   Does this holdup?)
-    3.1 from the above, we are looking at Private extensions.
-
-Need to look at dh_python2 and dh_python3
--- byte compiled modules must be generated in post-inst and removed in prerm
-
-Add 
-   X-Python-Version: >=2.7
-to the control section    --- done and added Python3 version as well
-
-According to https://www.debian.org/doc/packaging-manuals/python-policy/ch-embed.html,
-dpkg-shlibdeps will generate dependencies for things linking against the shared python library.
--- Need to look at that.
-
-
-https://www.debian.org/doc/packaging-manuals/python-policy/ap-build_dependencies.html
-Seems to suggest that we should have a Build-Depends on:
-  python-all-dev    --- done
-
-
-
-
diff --git a/doc/SConscript b/doc/SConscript
index a8927d8..4dc9129 100644
--- a/doc/SConscript
+++ b/doc/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -39,9 +39,10 @@ else:
     p=Popen([env['pythoncmd'], '-c', 'from __future__ import print_function;import matplotlib;print(matplotlib.__version__);from matplotlib.mlab import griddata;print("1")'], stdout=PIPE)
     try:
         mplversion=p.stdout.readline().strip()
-        haveMPL=True
-        hgd=p.stdout.readline().strip()
-        haveGD=True
+        if mplversion!='':
+           haveMPL=True
+           hgd=p.stdout.readline().strip()
+           haveGD=True
     except IOError:
         pass
     p.wait()
diff --git a/doc/completedevs.tex b/doc/completedevs.tex
index bc7374d..b0d964f 100644
--- a/doc/completedevs.tex
+++ b/doc/completedevs.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -19,13 +19,14 @@
 \begin{tabular}{r|lr|}
 & Releases\\ \cline{2-3}
 Cihan Altinay & 2.0 & Current \\
-Vince Boros & 3.2.1 & Current \\
 Joel Fenwick & 2.0 & Current \\
 Lutz Gross & 1.0 & Current \\
 Jaco du Plessis & 3.4.2 & Current \\
 Simon Shaw & 3.4.1 & Current \\
+	\cline{1-3}  	
 Artak Amirbekyan & 2.0 & 3.2.1 \\
 Imran Syed Azeezullah & 1.0 & 1.0 \\
+Vince Boros & 3.2.1 & 4.0 \\
 Paul Cochrane & 1.0 & 1.0 \\
 Matt Davies & 1.0 & 2.0 \\
 Lin Gao & 2.0 & 3.3 \\
diff --git a/doc/cookbook/SConscript b/doc/cookbook/SConscript
index c633513..429fab2 100644
--- a/doc/cookbook/SConscript
+++ b/doc/cookbook/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/cookbook/cookbook.bib b/doc/cookbook/cookbook.bib
index 07fc928..f98a93c 100644
--- a/doc/cookbook/cookbook.bib
+++ b/doc/cookbook/cookbook.bib
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/cookbook.tex b/doc/cookbook/cookbook.tex
index 0d69ec2..693b9ae 100644
--- a/doc/cookbook/cookbook.tex
+++ b/doc/cookbook/cookbook.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -22,6 +22,7 @@
 \input{cookbook_defs}
 \usepackage{upquote}    %used to precent LaTeX from mucking up '
 
+\input{verinfo}
 
 \ifpdf
 \pdfinfo {
@@ -45,8 +46,8 @@ The University of Queensland \\
 Brisbane, Australia \\
 Email: \email{esys at esscc.uq.edu.au}
 }                                                                                         
-\date{\today}
-\release{4.0}
+\date{\reldate}
+\release{\relver}
 %\release{development}
 
 \makeindex
@@ -65,7 +66,7 @@ Email: \email{esys at esscc.uq.edu.au}
 \fi
 
 \begin{center}
-Copyright (c) 2009--2014 by University of Queensland	\\
+Copyright (c) 2009--2015 by The University of Queensland	\\
 \url{http://www.uq.edu.au}				\\
 Primary Business: Queensland, Australia			\\
 Licensed under the Open Software License version 3.0	\\
diff --git a/doc/cookbook/cookbook_defs.tex b/doc/cookbook/cookbook_defs.tex
index d6ba1a2..5685b10 100644
--- a/doc/cookbook/cookbook_defs.tex
+++ b/doc/cookbook/cookbook_defs.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/einsteinETA.tex b/doc/cookbook/einsteinETA.tex
index 9fe7bbc..945ab50 100644
--- a/doc/cookbook/einsteinETA.tex
+++ b/doc/cookbook/einsteinETA.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/escpybas.tex b/doc/cookbook/escpybas.tex
index 0ca220a..778e55d 100644
--- a/doc/cookbook/escpybas.tex
+++ b/doc/cookbook/escpybas.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example01.tex b/doc/cookbook/example01.tex
index 3884f67..fd1cb2f 100644
--- a/doc/cookbook/example01.tex
+++ b/doc/cookbook/example01.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -586,7 +586,7 @@ The total energy should stay constant for the example discussed here.
 The script presented so far is available under 
 \verb|example01a.py|. You can edit this file with your favourite text editor. 
 On most operating systems\footnote{The \texttt{run-escript} launcher is not
-supported under {\it MS Windows} yet.} you can use the
+supported under {\it MS Windows}.} you can use the
 \program{run-escript} command 
 to launch {\it escript} scripts. For the example script use;
 \begin{verbatim}
diff --git a/doc/cookbook/example02.tex b/doc/cookbook/example02.tex
index 616b60c..4e0ca3a 100644
--- a/doc/cookbook/example02.tex
+++ b/doc/cookbook/example02.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example03.tex b/doc/cookbook/example03.tex
index dfa4e00..336e3e7 100644
--- a/doc/cookbook/example03.tex
+++ b/doc/cookbook/example03.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example04.tex b/doc/cookbook/example04.tex
index 8247ee6..29fe5bc 100644
--- a/doc/cookbook/example04.tex
+++ b/doc/cookbook/example04.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example05.tex b/doc/cookbook/example05.tex
index 831e072..0fc15b5 100644
--- a/doc/cookbook/example05.tex
+++ b/doc/cookbook/example05.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example07.tex b/doc/cookbook/example07.tex
index 6f9a227..e3eb512 100644
--- a/doc/cookbook/example07.tex
+++ b/doc/cookbook/example07.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example08.tex b/doc/cookbook/example08.tex
index dd4ec01..c2e3b21 100644
--- a/doc/cookbook/example08.tex
+++ b/doc/cookbook/example08.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example09.tex b/doc/cookbook/example09.tex
index a4b1d4f..ff21b63 100644
--- a/doc/cookbook/example09.tex
+++ b/doc/cookbook/example09.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example10.tex b/doc/cookbook/example10.tex
index b0924e2..e059bc5 100644
--- a/doc/cookbook/example10.tex
+++ b/doc/cookbook/example10.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/example11.tex b/doc/cookbook/example11.tex
index 6522a69..2419204 100644
--- a/doc/cookbook/example11.tex
+++ b/doc/cookbook/example11.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/intro.tex b/doc/cookbook/intro.tex
index 973be70..2445952 100644
--- a/doc/cookbook/intro.tex
+++ b/doc/cookbook/intro.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -89,10 +89,5 @@ provide a basis for users to develop their own models while at the same time
 demonstrating the steps required to completely solve and visualise the PDE
 problems.
 
-% All of the examples in this cookbook have been developed on a Linux based
-% operating system. 
-% Unfortunately Windows and Mac support cannot be guaranteed. However, in most
-% cases minor modifications to the scripts will generally solve any problems.
-
 \input{quickstart}
 \input{escpybas}
diff --git a/doc/cookbook/quickstart.tex b/doc/cookbook/quickstart.tex
index c1d1212..a5e9ac6 100644
--- a/doc/cookbook/quickstart.tex
+++ b/doc/cookbook/quickstart.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/cookbook/verinfo.tex b/doc/cookbook/verinfo.tex
new file mode 100644
index 0000000..e509a29
--- /dev/null
+++ b/doc/cookbook/verinfo.tex
@@ -0,0 +1,7 @@
+
+\newcommand{\relver}{development}
+\newcommand{\reldate}{\today}
+
+
+%\newcommand{\relver}{4.0}
+%\newcommand{\reldate}{\today}
diff --git a/doc/copyrights.tex b/doc/copyrights.tex
index 5e5b332..4922f35 100644
--- a/doc/copyrights.tex
+++ b/doc/copyrights.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 \begin{center}
-Copyright (c) 2003-2014 by University of Queensland\\
+Copyright (c) 2003-2015 by The University of Queensland\\
 \url{http://www.uq.edu.au}\\
 Primary Business: Queensland, Australia\\
 Licensed under the Open Software License version 3.0\\
diff --git a/doc/currentdev.tex b/doc/currentdev.tex
index 873c0d4..3ab47d4 100644
--- a/doc/currentdev.tex
+++ b/doc/currentdev.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -20,7 +20,7 @@
 \vspace{0.5cm}
 
 Escript is the product of years of work by many people.
-The active researchers for the current release series (3.x, 4.0) are listed
+The active researchers for the current release series (4.x) are listed
 here in alphabetical order.
 While development is collaborative, each person is listed with some of their
 major contributions --- this list is not exhaustive.
@@ -32,7 +32,6 @@ guide.
 \vspace{1cm}
 \begin{description}
 \item[Cihan Altinay] \weipa visualisation package, SCons build system rework, \ripley and CUDA solvers.
-\item[Vince Boros] Magnetism.
 \item[Joel Fenwick] Lazy evaluation, maintenance of escript module, release wrangler.
 \item[Lutz Gross] Patriarch, technical lead, solvers, large chunks of the original code.
 \item[Jaco du Plessis] Symbolic toolbox, GMSH reader MPI implementation, DC resistivity.
diff --git a/doc/docguide.tex b/doc/docguide.tex
index d4f5f7f..5c14008 100644
--- a/doc/docguide.tex
+++ b/doc/docguide.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/doxygen/SConscript b/doc/doxygen/SConscript
index c1aa741..30df54d 100644
--- a/doc/doxygen/SConscript
+++ b/doc/doxygen/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/elist.tex b/doc/elist.tex
index 3c48a03..b5dbb88 100644
--- a/doc/elist.tex
+++ b/doc/elist.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/epydoc/SConscript b/doc/epydoc/SConscript
index 8b73be9..74adbec 100644
--- a/doc/epydoc/SConscript
+++ b/doc/epydoc/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/examples/SConscript b/doc/examples/SConscript
index f236df4..570cc3b 100644
--- a/doc/examples/SConscript
+++ b/doc/examples/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -76,5 +76,5 @@ for single_processor_only in [True, False]:
       runs=[]
       for i in example_files:
           if i.startswith(d) and i.endswith('.py') and (single_processor_only == (i in example_files_no_mpi)): runs.append(os.path.split(i)[1])
-      TestGroups.append(GroupTest("$PYTHONRUNNER ",(),"",os.path.join("$BUILD_DIR/doc/examples/test",d),runs, single_processor_only=single_processor_only))
+      TestGroups.append(GroupTest("$PYTHONRUNNER ",(),"",os.path.join("$BATCH_ROOT/doc/examples",d),runs, single_processor_only=single_processor_only))
 
diff --git a/doc/examples/cookbook/cblib.py b/doc/examples/cookbook/cblib.py
index 23a6cfb..e2ff712 100644
--- a/doc/examples/cookbook/cblib.py
+++ b/doc/examples/cookbook/cblib.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -51,7 +51,7 @@ def toRegGrid(u, nx=50, ny=50):
    yi = np.linspace(inf(xx[1]),sup(xx[1]),ny)
 
    # interpolate u to grid
-   zi = pl.matplotlib.mlab.griddata(coordX,coordY,utemp,xi,yi)
+   zi = pl.matplotlib.mlab.griddata(coordX,coordY,utemp,xi,yi, interp='linear')
    return xi, yi, zi
 
 def subsample(u, nx=50, ny=50):
diff --git a/doc/examples/cookbook/cblib1.py b/doc/examples/cookbook/cblib1.py
index ac22834..cd33ece 100644
--- a/doc/examples/cookbook/cblib1.py
+++ b/doc/examples/cookbook/cblib1.py
@@ -2,7 +2,7 @@ from __future__ import print_function
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example01a.py b/doc/examples/cookbook/example01a.py
index 6b32fbc..4a9075a 100644
--- a/doc/examples/cookbook/example01a.py
+++ b/doc/examples/cookbook/example01a.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example01b.py b/doc/examples/cookbook/example01b.py
index bd37c6b..1d62620 100644
--- a/doc/examples/cookbook/example01b.py
+++ b/doc/examples/cookbook/example01b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example01c.py b/doc/examples/cookbook/example01c.py
index 45b3967..5327ee0 100644
--- a/doc/examples/cookbook/example01c.py
+++ b/doc/examples/cookbook/example01c.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example02.py b/doc/examples/cookbook/example02.py
index a9b00c9..538057d 100644
--- a/doc/examples/cookbook/example02.py
+++ b/doc/examples/cookbook/example02.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example03a.py b/doc/examples/cookbook/example03a.py
index 3517b7c..b706b5c 100644
--- a/doc/examples/cookbook/example03a.py
+++ b/doc/examples/cookbook/example03a.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example03b.py b/doc/examples/cookbook/example03b.py
index 83873b1..09a25c5 100644
--- a/doc/examples/cookbook/example03b.py
+++ b/doc/examples/cookbook/example03b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example04a.py b/doc/examples/cookbook/example04a.py
index 5c37da3..8f378ef 100644
--- a/doc/examples/cookbook/example04a.py
+++ b/doc/examples/cookbook/example04a.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example04b.py b/doc/examples/cookbook/example04b.py
index 6bf6e64..e1b5188 100644
--- a/doc/examples/cookbook/example04b.py
+++ b/doc/examples/cookbook/example04b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -55,7 +55,13 @@ if getMPISizeWorld() > 1:
 	print("This example will not run in an MPI world.")
 	sys.exit(0)
 
-if HAVE_FINLEY:
+try:
+    from mpl_toolkits.natgrid import _natgrid
+    HAVE_NATGRID=True
+except ImportError:
+    HAVE_NATGRID=False
+
+if HAVE_FINLEY and HAVE_NATGRID:
     # make sure path exists
     save_path= os.path.join("data","example04")
     mkDir(save_path)
diff --git a/doc/examples/cookbook/example05a.py b/doc/examples/cookbook/example05a.py
index 7db8d3c..e97aa4d 100644
--- a/doc/examples/cookbook/example05a.py
+++ b/doc/examples/cookbook/example05a.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -56,7 +56,13 @@ if getMPISizeWorld() > 1:
         print("This example will not run in an MPI world.")
         sys.exit(0)
 
-if HAVE_FINLEY:
+try:
+    from mpl_toolkits.natgrid import _natgrid
+    HAVE_NATGRID=True
+except ImportError:
+    HAVE_NATGRID=False
+
+if HAVE_FINLEY and HAVE_NATGRID:
     #################################################ESTABLISHING VARIABLES
     #set modal to 1 for a syncline or -1 for an anticline structural 
     #configuration
diff --git a/doc/examples/cookbook/example05b.py b/doc/examples/cookbook/example05b.py
index 2abd21f..027b610 100644
--- a/doc/examples/cookbook/example05b.py
+++ b/doc/examples/cookbook/example05b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example05c.py b/doc/examples/cookbook/example05c.py
index b116efd..00c620e 100644
--- a/doc/examples/cookbook/example05c.py
+++ b/doc/examples/cookbook/example05c.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example06.py b/doc/examples/cookbook/example06.py
index 829400e..247c102 100644
--- a/doc/examples/cookbook/example06.py
+++ b/doc/examples/cookbook/example06.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example07a.py b/doc/examples/cookbook/example07a.py
index 6d0556f..9b65cd7 100644
--- a/doc/examples/cookbook/example07a.py
+++ b/doc/examples/cookbook/example07a.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example07b.py b/doc/examples/cookbook/example07b.py
index a70d477..9dcdf50 100644
--- a/doc/examples/cookbook/example07b.py
+++ b/doc/examples/cookbook/example07b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example08a.py b/doc/examples/cookbook/example08a.py
index 31ea458..ba88e06 100644
--- a/doc/examples/cookbook/example08a.py
+++ b/doc/examples/cookbook/example08a.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example08b.py b/doc/examples/cookbook/example08b.py
index 557cae2..b853fa4 100644
--- a/doc/examples/cookbook/example08b.py
+++ b/doc/examples/cookbook/example08b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example08c.py b/doc/examples/cookbook/example08c.py
index d511993..13d213e 100644
--- a/doc/examples/cookbook/example08c.py
+++ b/doc/examples/cookbook/example08c.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example09a.py b/doc/examples/cookbook/example09a.py
index 19e276c..4d7d539 100644
--- a/doc/examples/cookbook/example09a.py
+++ b/doc/examples/cookbook/example09a.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example09b.py b/doc/examples/cookbook/example09b.py
index d8a153a..9b0269d 100644
--- a/doc/examples/cookbook/example09b.py
+++ b/doc/examples/cookbook/example09b.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example09c.py b/doc/examples/cookbook/example09c.py
index 0876d3e..fa7befc 100644
--- a/doc/examples/cookbook/example09c.py
+++ b/doc/examples/cookbook/example09c.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example09m.py b/doc/examples/cookbook/example09m.py
index fcee0d8..df81b25 100644
--- a/doc/examples/cookbook/example09m.py
+++ b/doc/examples/cookbook/example09m.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example09n.py b/doc/examples/cookbook/example09n.py
index efc84d1..b4eea32 100644
--- a/doc/examples/cookbook/example09n.py
+++ b/doc/examples/cookbook/example09n.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10a.py b/doc/examples/cookbook/example10a.py
index f10ede0..45ba148 100644
--- a/doc/examples/cookbook/example10a.py
+++ b/doc/examples/cookbook/example10a.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10b.py b/doc/examples/cookbook/example10b.py
index 20c4a25..72a656c 100644
--- a/doc/examples/cookbook/example10b.py
+++ b/doc/examples/cookbook/example10b.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10c_0.py b/doc/examples/cookbook/example10c_0.py
index 4f261f2..f549599 100644
--- a/doc/examples/cookbook/example10c_0.py
+++ b/doc/examples/cookbook/example10c_0.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10c_1.py b/doc/examples/cookbook/example10c_1.py
index 83b102e..430b883 100644
--- a/doc/examples/cookbook/example10c_1.py
+++ b/doc/examples/cookbook/example10c_1.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10d.py b/doc/examples/cookbook/example10d.py
index 0e63c42..5a5bc17 100644
--- a/doc/examples/cookbook/example10d.py
+++ b/doc/examples/cookbook/example10d.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10e.py b/doc/examples/cookbook/example10e.py
index 174a926..fd61ba9 100644
--- a/doc/examples/cookbook/example10e.py
+++ b/doc/examples/cookbook/example10e.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10m.py b/doc/examples/cookbook/example10m.py
index eab4218..bbd484e 100644
--- a/doc/examples/cookbook/example10m.py
+++ b/doc/examples/cookbook/example10m.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example10p.py b/doc/examples/cookbook/example10p.py
index 81cb5e0..841dc08 100644
--- a/doc/examples/cookbook/example10p.py
+++ b/doc/examples/cookbook/example10p.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example11a.py b/doc/examples/cookbook/example11a.py
index 4665cc7..c913422 100644
--- a/doc/examples/cookbook/example11a.py
+++ b/doc/examples/cookbook/example11a.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example11b.py b/doc/examples/cookbook/example11b.py
index 223991f..bf86ada 100644
--- a/doc/examples/cookbook/example11b.py
+++ b/doc/examples/cookbook/example11b.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example11c.py b/doc/examples/cookbook/example11c.py
index b294205..037c8cd 100644
--- a/doc/examples/cookbook/example11c.py
+++ b/doc/examples/cookbook/example11c.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/example11m.py b/doc/examples/cookbook/example11m.py
index e21de3d..2f7d14e 100644
--- a/doc/examples/cookbook/example11m.py
+++ b/doc/examples/cookbook/example11m.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/wave_stab.py b/doc/examples/cookbook/wave_stab.py
index a075049..a27e570 100644
--- a/doc/examples/cookbook/wave_stab.py
+++ b/doc/examples/cookbook/wave_stab.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/wavesolver2d001.py b/doc/examples/cookbook/wavesolver2d001.py
index b380107..2ba90d0 100644
--- a/doc/examples/cookbook/wavesolver2d001.py
+++ b/doc/examples/cookbook/wavesolver2d001.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/wavesolver2d002.py b/doc/examples/cookbook/wavesolver2d002.py
index 5ba9234..1fc43b4 100644
--- a/doc/examples/cookbook/wavesolver2d002.py
+++ b/doc/examples/cookbook/wavesolver2d002.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/wavesolver2d003.py b/doc/examples/cookbook/wavesolver2d003.py
index 07fe6f3..554481e 100644
--- a/doc/examples/cookbook/wavesolver2d003.py
+++ b/doc/examples/cookbook/wavesolver2d003.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/cookbook/wavesolver2d004.py b/doc/examples/cookbook/wavesolver2d004.py
index 07007dc..d327cba 100644
--- a/doc/examples/cookbook/wavesolver2d004.py
+++ b/doc/examples/cookbook/wavesolver2d004.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/geotutorial/backward_euler.py b/doc/examples/geotutorial/backward_euler.py
index e314f61..dff5f08 100644
--- a/doc/examples/geotutorial/backward_euler.py
+++ b/doc/examples/geotutorial/backward_euler.py
@@ -3,7 +3,7 @@ from __future__ import print_function
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/geotutorial/forward_euler.py b/doc/examples/geotutorial/forward_euler.py
index 3b30af0..9eaebad 100644
--- a/doc/examples/geotutorial/forward_euler.py
+++ b/doc/examples/geotutorial/forward_euler.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/geotutorial/myfirstscript.py b/doc/examples/geotutorial/myfirstscript.py
index 7fddc2f..ddd4254 100644
--- a/doc/examples/geotutorial/myfirstscript.py
+++ b/doc/examples/geotutorial/myfirstscript.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/geotutorial/steadystate.py b/doc/examples/geotutorial/steadystate.py
index 92a76c1..6bd3fd3 100644
--- a/doc/examples/geotutorial/steadystate.py
+++ b/doc/examples/geotutorial/steadystate.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/geotutorial/steadystate_variablek.py b/doc/examples/geotutorial/steadystate_variablek.py
index fa6af61..4f78a95 100644
--- a/doc/examples/geotutorial/steadystate_variablek.py
+++ b/doc/examples/geotutorial/steadystate_variablek.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/create_netcdf.py b/doc/examples/inversion/create_netcdf.py
index 004cfda..087a33b 100644
--- a/doc/examples/inversion/create_netcdf.py
+++ b/doc/examples/inversion/create_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/examples/inversion/dc_forward.py b/doc/examples/inversion/dc_forward.py
index ef8b914..1475f9d 100644
--- a/doc/examples/inversion/dc_forward.py
+++ b/doc/examples/inversion/dc_forward.py
@@ -78,10 +78,10 @@ sig_s.expand()
 
 
 schs=SchlumbergerSurvey(domain, sig_p, sig_s, current, a, n, midPoint, directionVector, numEle)
-pot=schs.getPotential()
-primaryApparentRes=schs.getApparentResistivityPrimary()
-SecondaryApparentRes=schs.getApparentResistivitySecondary()
-totalApparentRes=schs.getApparentResistivityTotal()
+pot=schs.getPotentialAnalytic()
+primaryApparentRes=schs.getApparentResistivity(pot[0])
+SecondaryApparentRes=schs.getApparentResistivity(pot[1])
+totalApparentRes=schs.getApparentResistivity(pot[2])
 
 
 n=1
@@ -89,4 +89,4 @@ print ("Total:\n")
 for i in totalApparentRes:
     print ("n = %d:"%n)
     print (i,"\n")
-    n=n+1
\ No newline at end of file
+    n=n+1
diff --git a/doc/examples/inversion/grav_ermapper.py b/doc/examples/inversion/grav_ermapper.py
index bb85a35..5b2bac1 100644
--- a/doc/examples/inversion/grav_ermapper.py
+++ b/doc/examples/inversion/grav_ermapper.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 
 """3D gravity inversion example using ER Mapper data"""
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/grav_netcdf.py b/doc/examples/inversion/grav_netcdf.py
index 18d1bba..845c4bb 100644
--- a/doc/examples/inversion/grav_netcdf.py
+++ b/doc/examples/inversion/grav_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 
 """3D gravity inversion example using netCDF data"""
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/gravmag_netcdf.py b/doc/examples/inversion/gravmag_netcdf.py
index 44dcfea..8535fb3 100644
--- a/doc/examples/inversion/gravmag_netcdf.py
+++ b/doc/examples/inversion/gravmag_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 
 """3D gravity/magnetic joint inversion example using netCDF data"""
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/gravmag_nodriver.py b/doc/examples/inversion/gravmag_nodriver.py
index 71da473..b31cbc4 100644
--- a/doc/examples/inversion/gravmag_nodriver.py
+++ b/doc/examples/inversion/gravmag_nodriver.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -20,7 +20,7 @@ Advanced 3D gravity/magnetic joint inversion example without using any
 inversion drivers
 """
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/gravmag_wgs84_nodriver.py b/doc/examples/inversion/gravmag_wgs84_nodriver.py
index 04eb9da..95157eb 100644
--- a/doc/examples/inversion/gravmag_wgs84_nodriver.py
+++ b/doc/examples/inversion/gravmag_wgs84_nodriver.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -20,7 +20,7 @@ Advanced 3D gravity/magnetic joint inversion example without using any
 inversion drivers
 """
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/mag_netcdf.py b/doc/examples/inversion/mag_netcdf.py
index 3e347e6..d6b4ddb 100644
--- a/doc/examples/inversion/mag_netcdf.py
+++ b/doc/examples/inversion/mag_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 
 """3D magnetic inversion example using netCDF data"""
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/mag_wgs84_netcdf.py b/doc/examples/inversion/mag_wgs84_netcdf.py
index eb56925..0ee0621 100644
--- a/doc/examples/inversion/mag_wgs84_netcdf.py
+++ b/doc/examples/inversion/mag_wgs84_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 
 """3D magnetic inversion example using netCDF data"""
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/plot_ermapper.py b/doc/examples/inversion/plot_ermapper.py
index a3e4e75..710f4e8 100644
--- a/doc/examples/inversion/plot_ermapper.py
+++ b/doc/examples/inversion/plot_ermapper.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/examples/inversion/plot_netcdf.py b/doc/examples/inversion/plot_netcdf.py
index e91b3b7..11a728b 100644
--- a/doc/examples/inversion/plot_netcdf.py
+++ b/doc/examples/inversion/plot_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/examples/inversion/strong_gravmag_netcdf.py b/doc/examples/inversion/strong_gravmag_netcdf.py
index a078d9d..43e0297 100644
--- a/doc/examples/inversion/strong_gravmag_netcdf.py
+++ b/doc/examples/inversion/strong_gravmag_netcdf.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 
 """3D gravity/magnetic joint inversion example using netCDF data"""
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/synthetic_HTI.py b/doc/examples/inversion/synthetic_HTI.py
index c49118b..6096f28 100644
--- a/doc/examples/inversion/synthetic_HTI.py
+++ b/doc/examples/inversion/synthetic_HTI.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/synthetic_TTI.py b/doc/examples/inversion/synthetic_TTI.py
index 03137bb..71d10e9 100644
--- a/doc/examples/inversion/synthetic_TTI.py
+++ b/doc/examples/inversion/synthetic_TTI.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/synthetic_VTI.py b/doc/examples/inversion/synthetic_VTI.py
index 7342390..ea9fb5f 100644
--- a/doc/examples/inversion/synthetic_VTI.py
+++ b/doc/examples/inversion/synthetic_VTI.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/synthetic_sonic.py b/doc/examples/inversion/synthetic_sonic.py
index 5771b16..5c1d4e3 100644
--- a/doc/examples/inversion/synthetic_sonic.py
+++ b/doc/examples/inversion/synthetic_sonic.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/inversion/synthetic_sonicHTI.py b/doc/examples/inversion/synthetic_sonicHTI.py
index f2a86b1..53909e4 100644
--- a/doc/examples/inversion/synthetic_sonicHTI.py
+++ b/doc/examples/inversion/synthetic_sonicHTI.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/brick.py b/doc/examples/usersguide/brick.py
index eb6b84f..44e62e9 100644
--- a/doc/examples/usersguide/brick.py
+++ b/doc/examples/usersguide/brick.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/brick_stl.py b/doc/examples/usersguide/brick_stl.py
index ebfc77b..c89a507 100644
--- a/doc/examples/usersguide/brick_stl.py
+++ b/doc/examples/usersguide/brick_stl.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/darcy.py b/doc/examples/usersguide/darcy.py
index cdb2b06..c1b3b1b 100644
--- a/doc/examples/usersguide/darcy.py
+++ b/doc/examples/usersguide/darcy.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/diffusion.py b/doc/examples/usersguide/diffusion.py
index 6be5fe6..e5638a0 100644
--- a/doc/examples/usersguide/diffusion.py
+++ b/doc/examples/usersguide/diffusion.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/fluid.py b/doc/examples/usersguide/fluid.py
index 0946379..419c5f4 100644
--- a/doc/examples/usersguide/fluid.py
+++ b/doc/examples/usersguide/fluid.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2008-2014 by University of Queensland
+# Copyright (c) 2008-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/examples/usersguide/heatedblock.py b/doc/examples/usersguide/heatedblock.py
index bc8c597..eb51ea3 100644
--- a/doc/examples/usersguide/heatedblock.py
+++ b/doc/examples/usersguide/heatedblock.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/helmholtz.py b/doc/examples/usersguide/helmholtz.py
index 26fd0af..464140c 100644
--- a/doc/examples/usersguide/helmholtz.py
+++ b/doc/examples/usersguide/helmholtz.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/int_save.py b/doc/examples/usersguide/int_save.py
index 7c0a8a0..22c925a 100644
--- a/doc/examples/usersguide/int_save.py
+++ b/doc/examples/usersguide/int_save.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/lid_driven_cavity.py b/doc/examples/usersguide/lid_driven_cavity.py
index 4f2e55d..6cebfad 100644
--- a/doc/examples/usersguide/lid_driven_cavity.py
+++ b/doc/examples/usersguide/lid_driven_cavity.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/mount.py b/doc/examples/usersguide/mount.py
index fe2ab04..e1b268a 100644
--- a/doc/examples/usersguide/mount.py
+++ b/doc/examples/usersguide/mount.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/poisson.py b/doc/examples/usersguide/poisson.py
index 6d8e26a..2f9e856 100644
--- a/doc/examples/usersguide/poisson.py
+++ b/doc/examples/usersguide/poisson.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/poisson_matplotlib.py b/doc/examples/usersguide/poisson_matplotlib.py
index e2ff6f6..9d5e306 100644
--- a/doc/examples/usersguide/poisson_matplotlib.py
+++ b/doc/examples/usersguide/poisson_matplotlib.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import division
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/poisson_vtk.py b/doc/examples/usersguide/poisson_vtk.py
index b2eff19..ff50400 100644
--- a/doc/examples/usersguide/poisson_vtk.py
+++ b/doc/examples/usersguide/poisson_vtk.py
@@ -1,7 +1,7 @@
 from __future__ import division, print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division, print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/quad.py b/doc/examples/usersguide/quad.py
index bf12d15..9ca20a7 100644
--- a/doc/examples/usersguide/quad.py
+++ b/doc/examples/usersguide/quad.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/refine.py b/doc/examples/usersguide/refine.py
index bcd5494..aa3af6b 100644
--- a/doc/examples/usersguide/refine.py
+++ b/doc/examples/usersguide/refine.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/slip.py b/doc/examples/usersguide/slip.py
index 3f0d766..3758b3f 100644
--- a/doc/examples/usersguide/slip.py
+++ b/doc/examples/usersguide/slip.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/trapezoid.py b/doc/examples/usersguide/trapezoid.py
index d6cfc53..da04755 100644
--- a/doc/examples/usersguide/trapezoid.py
+++ b/doc/examples/usersguide/trapezoid.py
@@ -1,7 +1,7 @@
 from __future__ import division
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/examples/usersguide/wave.py b/doc/examples/usersguide/wave.py
index 31bbfba..38df722 100644
--- a/doc/examples/usersguide/wave.py
+++ b/doc/examples/usersguide/wave.py
@@ -2,7 +2,7 @@ from __future__ import division
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/doc/install/SConscript b/doc/install/SConscript
index 365b436..d6e95e9 100644
--- a/doc/install/SConscript
+++ b/doc/install/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/install/allsrccommon.tex b/doc/install/allsrccommon.tex
index 82943b3..f607287 100644
--- a/doc/install/allsrccommon.tex
+++ b/doc/install/allsrccommon.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/binary.tex b/doc/install/binary.tex
deleted file mode 100644
index 216bf50..0000000
--- a/doc/install/binary.tex
+++ /dev/null
@@ -1,80 +0,0 @@
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
-% http://www.uq.edu.au
-%
-% Primary Business: Queensland, Australia
-% Licensed under the Open Software License version 3.0
-% http://www.opensource.org/licenses/osl-3.0.php
-%
-% Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-% Development 2012-2013 by School of Earth Sciences
-% Development from 2014 by Centre for Geoscience Computing (GeoComp)
-%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-
-\chapter{Binary Installation}\label{chap:bin}
-
-Binary distributions (no compilation required) are available for Windows(Section~\ref{sec:binwin}) 
-and ``recent'' Debian and Ubuntu releases.
-
-Debian (i386 or amd64):
-\begin{itemize}
- \item $6$ --- \emph{Squeeze}
- \item $?$ --- \emph{Wheezy}
-\end{itemize}
-
-Ubuntu (i386 or amd64):
-\begin{itemize}
- \item $11.10$ --- \emph{Oneiric} Ocelot
- \item $12.04$ --- \emph{Precise} Pangolin (LTS)
- \item $12.10$ --- \emph{Quantal} Queztal 
- \item $13.04$ --- \emph{Raring} Rabbit
-\end{itemize}
-
-
-We produce \texttt{.deb}s for the i386 and amd64 architectures for Debian stable(``squeeze'') and the 
-following Ubuntu releases:
-\begin{itemize}
- \item $11.10$ --- \emph{Oneiric} Ocelot
- \item $12.04$ --- \emph{Precise} Pangolin (LTS)
- \item $12.10$ --- \emph{Quantal} Queztal 
-\end{itemize}
-
-The package file will be named \file{escript-X-D_A.deb} where \texttt{X} is the version, \texttt{D} 
-is the distribution codename (eg ``\texttt{squeeze}'' or ``\texttt{oneric}'') and \texttt{A} is the architecture.
-For example, \file{escript-3.4-1-squeeze_amd64.deb} would be the file for squeeze for 64bit processors.
-To install \esfinley download the appropriate \file{.deb} file and execute the following 
-commands as root (you need to be in the directory containing the file):
-
-\begin{verse}
-\textbf{(For Ubuntu users)}\\
-You will need to either install \texttt{aptitude}\footnote{Unless you are short on disk space \texttt{aptitude} is recommended} or substitute \texttt{apt-get} where this guide uses \texttt{aptitude}.
-\begin{shellCode}
-sudo apt-get install aptitude
-\end{shellCode}
-\end{verse}
-
-\begin{shellCode}
-dpkg --unpack escript*.deb
-aptitude install escript
-\end{shellCode}
-
-Installing escript should not remove any packages from your system.
-If aptitude suggests removing escript, then choose 'N'.
-It should then suggest installing some dependencies choose 'Y' here.
-If it suggests removing \texttt{escript-noalias} then agree.
-
-If you use sudo (for example on Ubuntu) enter the following instead:
-\begin{shellCode}
-sudo dpkg --unpack escript*.deb
-sudo aptitude install escript
-\end{shellCode}
-
-This should install \esfinley and its dependencies on your system.
-Please notify the development team if something goes wrong.
-
-\input{binwin.tex}
-
-
diff --git a/doc/install/bincommon.tex b/doc/install/bincommon.tex
deleted file mode 100644
index fcaf4e5..0000000
--- a/doc/install/bincommon.tex
+++ /dev/null
@@ -1,31 +0,0 @@
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
-% http://www.uq.edu.au
-%
-% Primary Business: Queensland, Australia
-% Licensed under the Open Software License version 3.0
-% http://www.opensource.org/licenses/osl-3.0.php
-%
-% Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-% Development 2012-2013 by School of Earth Sciences
-% Development from 2014 by Centre for Geoscience Computing (GeoComp)
-%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% material common to all binary distributions.
-
-\chapter{Binary releases}\label{chap:bin}
-
-Binary distributions (no compilation required) are available for the following operating systems:
-\begin{itemize}
- \item \linux~-- Section~\ref{sec:binlinux}
- \item \macosx~-- Section~\ref{sec:binmac}
- \item Windows~-- Section~\ref{sec:binwin}.
-\end{itemize}
-
-Note that only the Debian/Ubuntu binary packages support \openmp and \mpi.
-If you need these features you will need to compile \esfinley from source (see Section~\ref{sec:compilesrc} 
-and Section~\ref{sec:compileescriptlinux}.)
-
-
-\input{binlinux}
diff --git a/doc/install/binlinux.tex b/doc/install/binlinux.tex
index a948f17..69ad418 100644
--- a/doc/install/binlinux.tex
+++ b/doc/install/binlinux.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/binmac.tex b/doc/install/binmac.tex
index 6f08d0a..a32c199 100644
--- a/doc/install/binmac.tex
+++ b/doc/install/binmac.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/binwin.tex b/doc/install/binwin.tex
deleted file mode 100644
index 0891aa0..0000000
--- a/doc/install/binwin.tex
+++ /dev/null
@@ -1,49 +0,0 @@
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
-% http://www.uq.edu.au
-%
-% Primary Business: Queensland, Australia
-% Licensed under the Open Software License version 3.0
-% http://www.opensource.org/licenses/osl-3.0.php
-%
-% Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-% Development 2012-2013 by School of Earth Sciences
-% Development from 2014 by Centre for Geoscience Computing (GeoComp)
-%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Windows binary installation}
-\label{sec:binwin}
-
-There is no automated install/uninstall procedure for \esfinley on Windows at this time.
-This version release was made on Windows~XP and has not been tested on newer versions.
-If you want to use MPI, make sure to download the MPI version [You will also need 
-MPICH2 1.0.8 (\url{http://www.mcs.anl.gov/research/projects/mpich2/})].
-Other dependencies are:
-\begin{itemize}
- \item pythonxy (\url{http://www.pythonxy.com}) or 
-  \begin{itemize}
-	\item Python 2.5.4 (\url{http://python.org})
-	\item Numpy 1.3.0 (\url{http://sourceforge.net/projects/numpy/files/NumPy})
-	\item SymPy 0.7.1 (\url{http://sympy.org})
-  \end{itemize}
-  \item Optional:
-  \begin{itemize}
-      \item gmsh 2.4.0 (required to use pycad, must be in your PATH) - \url{http://www.geuz.org/gmsh}
-    \item matplotlib 0.99 - \url{http://matplotlib.sourceforge.net}
-  \end{itemize}
-\end{itemize}
-
-
-Unpack the escript zip file, then:
-\begin{itemize}
-\item 
- copy the \file{esys} directory to your Python 2.5 site-packages folder\footnote{Substitute the relevant
- Python version}
- (usually \file{C:\textbackslash Python25\textbackslash Lib\textbackslash site-packages}).
-\item 
- copy the \file{.dll} files from \file{esys\_dlls} to a directory on your PATH. For example copy the directory to \file{C:\textbackslash Python25\textbackslash libs\textbackslash esys\_dlls} and add  \file{C:\textbackslash Python25\textbackslash libs\textbackslash esys\_dlls} to your PATH.\footnote{Failing to do so my result in the error message:
-``This application has failed to start because the boost_python-vc71-mt-1_33_1.dll was not found.''
-}
-\end{itemize}
-
diff --git a/doc/install/chcomp.tex b/doc/install/chcomp.tex
index 17aaa7c..c1c1c41 100644
--- a/doc/install/chcomp.tex
+++ b/doc/install/chcomp.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2014 by University of Queensland
+% Copyright (c) 2014-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/compiler.tex b/doc/install/compiler.tex
index bf81a7e..b792157 100644
--- a/doc/install/compiler.tex
+++ b/doc/install/compiler.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/debbin.tex b/doc/install/debbin.tex
index d1a2e59..c57dff8 100644
--- a/doc/install/debbin.tex
+++ b/doc/install/debbin.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -16,24 +16,40 @@
 
 \chapter{Debian/Ubuntu Binary Installation}\label{chap:bin}
 
-We provide \texttt{.deb} files for the following distributions:
+We provide \texttt{.deb} files for the following distributions\footnote{While we endevour to comply with current debian policy 
+for producing packages, we do not make any promises.}:
 
 Debian (i386 or amd64):
 \begin{itemize}
  \item $7$ --- \emph{Wheezy}
+ \item $8$ --- \emph{Jessie}
 \end{itemize}
 
 Ubuntu (i386 or amd64):
 \begin{itemize}
  \item $14.04$ --- \emph{Trusty} Tahr (LTS)
- \item $14.10$ --- \emph{Utopic} Unicorn 
+% \item $14.10$ --- \emph{Utopic} Unicorn 
+ \item $15.04$ --- \emph{Vivid} Vervet
 \end{itemize}
 
 Two packages make up the \escript system:
-The main package which contains all system itself and the (optional) documentation package.
+\begin{itemize}
+ \item Escript documentation (python-escript-doc). This is optional.
+ \item Escript programs and libraries. You only need one of these, choose the one\footnote{You can 
+ have a number of these packages installed at the same time. To choose which one is executed, 
+ use a different launcher script: run-escript2, run-escript2-mpi, run-escript3, run-escript3-mpi.} which matches your needs.
+ \begin{itemize}
+  \item python-escript --- Python2 with OpenMP threaded parallelism.
+  \item python-escript-mpi --- Python2 with MPI and OpenMP
+  \item python3-escript --- Python3 with OpenMP
+  \item python3-escript-mpi --- Python2 with MPI and OpenMP
+ \end{itemize}
+ Substitute your chosen package in the instructions below.
+\end{itemize}
+
 The main package will be named \file{python-escript-X-D_A.deb} where \texttt{X} is the version, \texttt{D} 
 is the distribution codename (eg ``\texttt{wheezy}'' or ``\texttt{trusty}'') and \texttt{A} is the architecture.
-For example, \file{python-escript-3.4-1-trusty_amd64.deb} would be the file for Ubuntu $14.04$ for 64bit processors.
+For example, \file{python-escript-4.1-1-trusty_amd64.deb} would be the Python2 file for Ubuntu $14.04$ for 64bit processors.
 There is a common documentation for all distributions called \file{python-escript-doc-X_all.deb}.
 To install \esfinley, download the appropriate \file{.deb} file(s) and execute the following 
 commands as root (you need to be in the directory containing the file):
diff --git a/doc/install/install.tex b/doc/install/install.tex
index 1b2e740..6ac37ac 100644
--- a/doc/install/install.tex
+++ b/doc/install/install.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -20,6 +20,8 @@
 %Previous LaTeX was replacing them with non python slanty quotes
 \usepackage{comment}
 
+\input{verinfo}
+
 \title{Installation guide for \emph{esys-Escript}}
 
 \author{Escript development team}
@@ -29,8 +31,8 @@ The University of Queensland \\
 Brisbane, Australia \\
 Email: \email{esys at esscc.uq.edu.au}
 }
-\date{\today}      
-\release{4.0}
+\date{\reldate}      
+\release{\relver}
 %\release{development}
 
 \ifpdf
diff --git a/doc/install/install_defs.tex b/doc/install/install_defs.tex
index bfb21ee..24d88e2 100644
--- a/doc/install/install_defs.tex
+++ b/doc/install/install_defs.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -33,12 +33,11 @@
 \newcommand{\escript}{\module{esys.escript}\xspace}
 \newcommand{\finley}{\module{esys.finley}\xspace}
 \newcommand{\esys}{\module{esys}\xspace}
-\newcommand{\downunder}{\module{esys}\xspace}
+\newcommand{\downunder}{\module{esys.downunder}\xspace}
 
 \newcommand{\esfinley}{Escript\xspace}
 \newcommand{\linux}{Linux\xspace}
 \newcommand{\macosx}{MacOS~X\xspace}
-\newcommand{\winxp}{Windows~XP\xspace}
 \newcommand{\openmp}{OpenMP\xspace}
 \newcommand{\mpi}{MPI\xspace}
 
diff --git a/doc/install/intro.tex b/doc/install/intro.tex
index a3cb91f..bd04154 100644
--- a/doc/install/intro.tex
+++ b/doc/install/intro.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -28,7 +28,7 @@ It can be installed in two ways:
   \item Binary packages -- ready to run with no compilation required. These are available for recent Debian and Ubuntu distributions.
   \item From source -- that is, it must be compiled for your machine.
   This will be required if you are running anything other than Debian/Ubuntu 
-  or if extra functionality is required such as \mpi parallelisation.
+  or if extra functionality is required.
 \end{enumerate}
 
 See the site \url{https://answers.launchpad.net/escript-finley} for online help.
diff --git a/doc/install/source.tex b/doc/install/source.tex
index 4324dce..a0723c5 100644
--- a/doc/install/source.tex
+++ b/doc/install/source.tex
@@ -1,6 +1,6 @@
 %!TEX root = install.tex
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2012-2014 by University of Queensland
+% Copyright (c) 2012-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -123,7 +123,7 @@ sudo aptitude install python-sympy python-matplotlib python-scipy
 sudo aptitude install python-pyproj python-gdal 
 \end{shellCode}
 
-\noindent Once \textit{Jessie} is released (or if \textit{wheezy-backports} is in your \texttt{apt} sources) you can use:
+\noindent If you are running \textit{Jessie}, (or if \textit{wheezy-backports} is in your \texttt{apt} sources) you can use:
 \begin{shellCode}
 sudo aptitude install gmsh 
 \end{shellCode}
@@ -216,27 +216,22 @@ scons -j1 py_tests options_file=scons/templates/opensuse13.1_options.py
 These instructions were prepared using centos release $7.0$.
 The core of escript works, however some functionality is not availible because the default packages for some dependencies in Centos are too old.
 
-\noindent Install packages from the main distribution:
-\begin{shellCode}
-yum install python-devel numpy scipy scons boost-devel
-yum install python-matplotlib gcc gcc-c++
-yum install boost-python 
-\end{shellCode}
-
-The above packages will allow you to use most features except saving and loading files in \texttt{netCDF} 
-format and the \downunder inversion library.
-If you wish to use those features, you will need to install some additional packages.
-NetCDF needs to be installed when you compile if you wish to use it.
-\begin{optionalstep}
 \noindent Add the \texttt{EPEL} repository.
 \begin{shellCode}
 yum install epel-release.noarch
 \end{shellCode}
 
+\noindent Install packages:
 \begin{shellCode}
 yum install netcdf-devel netcdf_cxx_devel gdal-python
+yum install python-devel numpy scipy scons boost-devel
+yum install python-matplotlib gcc gcc-c++
+yum install boost-python 
 \end{shellCode}
-\end{optionalstep}
+
+The above packages will allow you to use most features except 
+the \downunder inversion library.
+If you wish to use those it, you will need to install some additional packages.
 
 \noindent For some coordinate transformations, \downunder can also make use of the python interface to a tool called \texttt{proj}.
 There does not seem to be an obvious centos repository for this though.
diff --git a/doc/install/srcadditional.tex b/doc/install/srcadditional.tex
index ba9b620..a597f78 100644
--- a/doc/install/srcadditional.tex
+++ b/doc/install/srcadditional.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/srclinux.tex b/doc/install/srclinux.tex
index fed635f..9d3ee45 100644
--- a/doc/install/srclinux.tex
+++ b/doc/install/srclinux.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/srcmac.tex b/doc/install/srcmac.tex
index 68c221b..770a8da 100644
--- a/doc/install/srcmac.tex
+++ b/doc/install/srcmac.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/install/srcommon.tex b/doc/install/srcommon.tex
deleted file mode 100644
index 91a299d..0000000
--- a/doc/install/srcommon.tex
+++ /dev/null
@@ -1,265 +0,0 @@
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
-% http://www.uq.edu.au
-%
-% Primary Business: Queensland, Australia
-% Licensed under the Open Software License version 3.0
-% http://www.opensource.org/licenses/osl-3.0.php
-%
-% Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-% Development 2012-2013 by School of Earth Sciences
-% Development from 2014 by Centre for Geoscience Computing (GeoComp)
-%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% This file contains material common to all src distributions.
-
-% The original version of this content came from the esscc twiki page maintained by ksteube
-
-This chapter describes how to build \esfinley from source assuming that the dependencies are already installed (for example using precompiled packages for your OS).
-Section~\ref{sec:deps} describes the dependencies, while Section~\ref{sec:compilesrc} gives the compile instructions.
-
-If you would prefer to build all the dependencies from source in the escript-support packages please see Chapter~\ref{chap:allsrc}.
-\esfinley is known to compile and run on the following systems:
-\begin{itemize}
- \item \linux using gcc
-\item \linux using icc on SGI ICE 8200. (We do not recommend building with intel-11)
-\item \macosx using gcc or clang
-\item \winxp using the Visual C compiler (we do not specifically discuss Windows builds in this guide).
-\end{itemize}
-
-If you have compiled a previous version of \esfinley, the \file{..._options.py} file has the same format
-as in the previous release, so you can reuse it.
-
-
-\section{External dependencies}
-\label{sec:deps}
-The following external packages are required in order to compile and run \esfinley.
-Where version numbers are specified, more recent versions can probably be substituted.
-You can either try the standard/precompiled packages available for your operating system or you can download and build them from source.
-The advantage of using existing packages is that they are more likely to work together properly.
-You must take greater care if downloading sources separately.
-
-\begin{itemize}
- \item python $\geq 2.6$ (\url{http://python.org}) \\-
-        Python interpreter (you must compile with shared libraries.)
- \item numpy $\geq 1.1.0$ (\url{http://numpy.scipy.org}) \\-
-        Arrays for Python
- \item boost $\geq 1.35$ (\url{http://www.boost.org}) \\-
-        Interface between C++ and Python
- \item scons $\geq 0.989.5$ (\url{http://www.scons.org/}) \\-
-        Python-based alternative to \texttt{make}.
-\end{itemize}
-
-The version numbers given here are not strict requirements, more recent (and in some cases older) versions are very likely to work.
-The following packages should be sufficient (but not necessarily minimal) for Debian 6.0 (``Squeeze''):
-\texttt{libboost-python-dev, scons, python-numpy, python-sympy, g++}.
-
-\noindent The following packages may be required for some of the optional capabilities of the system:
-\begin{itemize}
- \item sympy $\geq$ (\url{http://sympy.org}) \\-
-        Used by \texttt{esys.escript.symbolic}.
- \item netcdf $\geq 3.6.2$ (\url{http://www.unidata.ucar.edu/software/netcdf}) \\-
-        Used to save data sets in binary form for checkpoint/restart (must be compiled with -fPIC)
- \item parmetis $\geq 3.1$ (\url{http://glaros.dtc.umn.edu/gkhome/metis/parmetis/overview}) \\-
-        Optimization of the stiffness matrix
- \item MKL \\(\url{http://www.intel.com/cd/software/products/asmo-na/eng/307757.htm}) \\-
-        Intel's Math Kernel Library for use with their C compiler.
-\item Lapack - Available in various versions from various places. \\ 
-Currently only used to invert dense square matrices larger than 3x3. 
- \item gmsh $\geq 2.2.0$ (\url{http://www.geuz.org/gmsh}) \\-
-        Mesh generation and viewing [esys.pycad uses this]
-\end{itemize}
-
-\noindent Mesh generation: as well as \texttt{gmsh} above you could also use:
-\begin{itemize}
- \item triangle $\geq 1.6$ (\url{http://www.cs.cmu.edu/~quake/triangle.html}) \\-
-        Two-dimensional mesh generator and Delaunay triangulator.
-\end{itemize}
-
-Packages for visualization:
-\begin{itemize}
- \item mayavi $\geq 1.5$ (\url{http://mayavi.sourceforge.net}) \\-
-        MayaVi is referenced in our User's Guide for viewing VTK files
- \item visit $\geq 1.11.2$ (\url{https://wci.llnl.gov/codes/visit/}) \\-
-        A powerful visualisation system with movie-making capabilities.
-\end{itemize}
-
-
-
-The source code comes with an extensive set of unit tests. If you would like to
-build those to verify your installation you need:
-\begin{itemize}
- \item cppunit $\geq 1.12.1$ (\url{http://cppunit.sourceforge.net})
-\end{itemize}
-
-\section{Compilation}\label{sec:compilesrc}
-Throughout this section we will assume that the source code is uncompressed in a directory called \file{escript.d}.
-You can call the directory anything you like, provided that you make the change before you compile.
-
-You need to indicate where to find the external dependencies.
-To do this, create a file in the \file{escript.d/scons} directory called \file{x_options.py} where ``x'' is the name of your computer (output of the \texttt{hostname} command).
-Please note that if your hostname has non-alphanumeric characters in it (eg - ) you need to replace them with underscores.
-For example the options file for \texttt{bob-desktop} would be named \file{bob_desktop_options.py}.
-
-From now on all paths will be relative to the top level of the source.
-As a starting point copy the contents of one of the following files into your options file:
-\begin{itemize}
-\item \file{scons/TEMPLATE_linux.py} (\linux and \macosx desktop)
-\item \file{scons/TEMPLATE_windows.py} (\winxp)
-\end{itemize}
-
-This options file controls which features and libraries your build of escript will attempt to use.
-For example to use OpenMP or MPI you will need to enable it here.
-If you want to try escript out without customising your build, then change
-directories to \file{escript.d} and enter
-\begin{shellCode}
-scons 
-\end{shellCode}
-If this works you can skip to Section~\ref{sec:diff}.
-If not, then you will need to make some modications to the file.
-Read on.
-
-The template files contain all available options with a comment explaining the
-purpose of each.
-Check through the file and ensure that the relevant paths and names are correct
-for your system and that you enable optional components that you wish to use.
-For example, to use netCDF, find the netcdf-related lines, uncomment them
-(i.e. remove the \# at the beginning of the lines) and change them according
-to your installation:
-\begin{shellCode}
-netcdf = True
-netcdf_prefix = '/opt/netcdf4'
-netcdf_libs = ['netcdf_c++', 'netcdf']
-\end{shellCode}
-
-In this example, netCDF \emph{header} files must be located in
-\file{/opt/netcdf4/include}\footnote{or \ldots/include32 or \ldots/include64 or \ldots/inc}
-and the \emph{libraries} in \file{/opt/netcdf4/lib}\footnote{or \ldots/lib32 or \ldots/lib64}.
-If this scheme does not apply to your installation then you may also specify
-the include-path and library-path directly like so:
-\begin{shellCode}
-netcdf_prefix = ['/usr/local/include/netcdf', '/usr/local/lib']
-\end{shellCode}
-The order is important: the first element in the list is the
-\emph{include}-path, the second element is the \emph{library}-path and both
-must be specified.
-
-If a line in the options file is commented out and you do not require the
-feature, then it can be ignored.
-To actually compile (if you have $n$ processors, then you can use \texttt{scons -j$n$} instead):
-
-\begin{shellCode}
-cd escript.d
-scons
-\end{shellCode}
-
-As part of its output, scons will tell you the name of the options file it used
-as well as a list of features and whether they are enabled for your build.
-If you enabled an optional dependency and the library or include files could
-not be found you will be notified and the build will stop.
-
-Note, that you can override all settings from the options-file on the scons
-command line. For example, if you usually build an optimized version but would
-like to build a debug version into a separate directory without changing your
-default settings, you can use:
-\begin{shellCode}
-scons debug=1 prefix=debugbuild
-\end{shellCode}
-This will install the binaries and libraries built in debug mode into
-directories underneath \file{./debugbuild}.
-
-To run the unit test suite that comes with the source code issue
-\begin{shellCode}
-scons py_tests
-\end{shellCode}
-(If you have cppunit installed you can run additional tests using \texttt{scons all_tests}.
-
-Grab a coffee or two while the tests compile and run.
-An alternative method is available for running tests on \openmp and \mpi builds.
-
-\subsection{Compilation with \openmp}
-\openmp is generally enabled by setting compiler and linker switches. For the
-most common compilers these are automatically set by build system and all you
-have to do is set the \texttt{openmp} option to True in your options file. If
-this does not work or your compiler is different, then consult your compiler
-documentation for the precise switches to use and modify the \texttt{omp_flags}
-and \texttt{omp_ldflags} variables in your options file.
-For example, for gcc compilers which support \openmp use:
-\begin{shellCode}
-openmp = True
-omp_flags = '-fopenmp'
-omp_ldflags = '-fopenmp'
-\end{shellCode}
-(The two latter settings can also be left out as this is the default OpenMP on gcc.)
-
-You can test your \openmp-enabled build, e.g. using 4 threads by issuing
-\begin{shellCode}
-export ESCRIPT_NUM_THREADS=4
-scons py_tests
-\end{shellCode}
-
-\subsection{Compilation with \mpi}
-You need to have \mpi preinstalled on your system.
-There are a number of implementations so we do not provide any specific advice
-here.
-Set the following variables in your options file to according to your
-installation:
-\begin{itemize}
- \item \texttt{mpi} \\
-    which \mpi implementation (flavour) is used. Valid values are
-    \begin{itemize}
-        \item[\texttt{none}] \mpi is disabled
-        \item[\texttt{MPT}] SGI MPI implementation \\
-            \url{http://techpubs.sgi.com/library/manuals/3000/007-3687-010/pdf/007-3687-010.pdf}
-        \item[\texttt{MPICH}] Argonne's MPICH implementation \\
-            \url{http://www.mcs.anl.gov/research/projects/mpi/mpich1/}
-        \item[\texttt{MPICH2}] Argonne's MPICH version 2 implementation \\
-            \url{http://www.mcs.anl.gov/research/projects/mpi/mpich2/}
-        \item[\texttt{OPENMPI}] Open MPI \\
-            \url{http://www.open-mpi.org/}
-        \item[\texttt{INTELMPI}] Intel MPI \\
-            \url{http://software.intel.com/en-us/intel-mpi-library/}
-    \end{itemize}
- \item \texttt{mpi_prefix} \\
-    where to find \mpi headers and libraries (see netCDF example above)
- \item \texttt{mpi_libs} \\
-    which libraries to link to.
-\end{itemize}
-
-To test your build using 6 processes enter:
-\begin{shellCode}
-export ESCRIPT_NUM_PROCS=6
-scons py_tests
-\end{shellCode}
-and on $2$ processes with $4$ threads each (provided \openmp is enabled)\footnote{Unless your system has $8$ cores expect this to be slow}:
-\begin{shellCode}
-export ESCRIPT_NUM_THREADS=4
-export ESCRIPT_NUM_PROCS=2
-scons py_tests
-\end{shellCode}
-Alternatively, you can give a hostfile
-\begin{shellCode}
-export ESCRIPT_NUM_THREADS=4
-export ESCRIPT_HOSTFILE=myhostfile
-scons py_tests
-\end{shellCode}
-Note that depending on your \mpi flavour it may be required to start a daemon
-before running the tests under \mpi.
-
-\subsection{Difficulties}\label{sec:diff}
-
-\subsubsection{Mismatch of runtime and build libraries}
-Most external libraries used by \esfinley are linked dynamically.
-This can lead to problems if after compiling \esfinley these libraries are
-updated.
-The same applies to the installed Python executable and libraries.
-Whenever these dependencies change on your system you should recompile
-\esfinley to avoid problems at runtime such as load errors or segmentation
-faults.
-
-\subsubsection{\openmp builds segfault running examples}
-One known cause for this is linking the \file{gomp} library with escript built using gcc 4.3.3.
-While you need the \texttt{-fopenmp} switch you should not need to link \file{gomp}.
-
-
diff --git a/doc/install/verinfo.tex b/doc/install/verinfo.tex
new file mode 100644
index 0000000..e509a29
--- /dev/null
+++ b/doc/install/verinfo.tex
@@ -0,0 +1,7 @@
+
+\newcommand{\relver}{development}
+\newcommand{\reldate}{\today}
+
+
+%\newcommand{\relver}{4.0}
+%\newcommand{\reldate}{\today}
diff --git a/doc/install/winstall.tex b/doc/install/winstall.tex
deleted file mode 100644
index bf7f263..0000000
--- a/doc/install/winstall.tex
+++ /dev/null
@@ -1,48 +0,0 @@
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
-% http://www.uq.edu.au
-%
-% Primary Business: Queensland, Australia
-% Licensed under the Open Software License version 3.0
-% http://www.opensource.org/licenses/osl-3.0.php
-%
-% Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-% Development 2012-2013 by School of Earth Sciences
-% Development from 2014 by Centre for Geoscience Computing (GeoComp)
-%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\chapter{Windows binary installation}
-\label{chap:winstall}
-
-There is no automated install/uninstall procedure for \esfinley on Windows at this time.
-Where builds are available, they will be built for Windows~XP and has not been tested on newer versions.
-If you want to use MPI, make sure to download the MPI version [You will also need 
-MPICH2 1.0.8 (\url{http://www.mcs.anl.gov/research/projects/mpich2/})].
-Other dependencies are:
-\begin{itemize}
- \item pythonxy (\url{http://www.pythonxy.com}) or 
-  \begin{itemize}
-	\item Python 2.7 (\url{http://python.org})
-	\item Numpy 1.3.0 (\url{http://sourceforge.net/projects/numpy/files/NumPy})
-	\item SymPy 0.7.1 (\url{http://sympy.org})
-  \end{itemize}
-  \item Optional:
-  \begin{itemize}
-      \item gmsh 2.4.0 (required to use pycad, must be in your PATH) - \url{http://www.geuz.org/gmsh}
-    \item matplotlib 0.99 - \url{http://matplotlib.sourceforge.net}
-  \end{itemize}
-\end{itemize}
-
-
-Unpack the escript zip file, then:
-\begin{itemize}
-\item 
- copy the \file{esys} directory to your Python 2.7 site-packages folder\footnote{Substitute the relevant
- Python version}
- (usually \file{C:\textbackslash Python27\textbackslash Lib\textbackslash site-packages}).
-\item 
- copy the \file{.dll} files from \file{esys\_dlls} to a directory on your PATH. For example copy the directory to \file{C:\textbackslash Python27\textbackslash libs\textbackslash esys\_dlls} and add  \file{C:\textbackslash Python27\textbackslash libs\textbackslash esys\_dlls} to your PATH.\footnote{Failing to do so my result in the error message:
-``This application has failed to start because the boost_python-vc71-mt-1_33_1.dll was not found.''
-}
-\end{itemize}
\ No newline at end of file
diff --git a/doc/inversion/CookDcRes.tex b/doc/inversion/CookDcRes.tex
index 52d7086..486cf7f 100644
--- a/doc/inversion/CookDcRes.tex
+++ b/doc/inversion/CookDcRes.tex
@@ -1,6 +1,6 @@
 %!TEX root = inversion.tex
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/Forward2DMTTEMode.tex b/doc/inversion/Forward2DMTTEMode.tex
index 2cf18dc..c00f3b3 100644
--- a/doc/inversion/Forward2DMTTEMode.tex
+++ b/doc/inversion/Forward2DMTTEMode.tex
@@ -1,6 +1,6 @@
 %!TEX root = inversion.tex
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/ForwardDCRES.tex b/doc/inversion/ForwardDCRES.tex
index 1c56b4d..c7e53c3 100644
--- a/doc/inversion/ForwardDCRES.tex
+++ b/doc/inversion/ForwardDCRES.tex
@@ -1,6 +1,6 @@
 %!TEX root = inversion.tex
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/ForwardGravity.tex b/doc/inversion/ForwardGravity.tex
index a157854..124c539 100644
--- a/doc/inversion/ForwardGravity.tex
+++ b/doc/inversion/ForwardGravity.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/ForwardMagnetic.tex b/doc/inversion/ForwardMagnetic.tex
index 7d67851..636c4c8 100644
--- a/doc/inversion/ForwardMagnetic.tex
+++ b/doc/inversion/ForwardMagnetic.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/ForwardSelfMagnetic.tex b/doc/inversion/ForwardSelfMagnetic.tex
index 3d33fe2..06f33cb 100644
--- a/doc/inversion/ForwardSelfMagnetic.tex
+++ b/doc/inversion/ForwardSelfMagnetic.tex
@@ -1,5 +1,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/Minimization.tex b/doc/inversion/Minimization.tex
index bcd6aa3..6f7057d 100644
--- a/doc/inversion/Minimization.tex
+++ b/doc/inversion/Minimization.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/SConscript b/doc/inversion/SConscript
index 2ab840b..b6fedaf 100644
--- a/doc/inversion/SConscript
+++ b/doc/inversion/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/inversion/defs.tex b/doc/inversion/defs.tex
index bd9fbfc..7182adb 100644
--- a/doc/inversion/defs.tex
+++ b/doc/inversion/defs.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/intro.tex b/doc/inversion/intro.tex
index 9c4410b..e73083f 100644
--- a/doc/inversion/intro.tex
+++ b/doc/inversion/intro.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/inversion/inversion.tex b/doc/inversion/inversion.tex
index 612e077..60e5a8e 100644
--- a/doc/inversion/inversion.tex
+++ b/doc/inversion/inversion.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -23,7 +23,7 @@
 \graphicspath{{figures/}}
 
 \input{defs}
-
+\input{verinfo}
 \makeindex
 
 \begin{document}
@@ -36,13 +36,13 @@
 The University of Queensland\\
 School of Earth Sciences\\
 St. Lucia, QLD 4072, Australia.}
-\release{4.0}
+\release{\relver}
 %\release{development}
 
 \maketitle
 
 \begin{center}
-Copyright (c) 2012--2014 by University of Queensland	\\
+Copyright (c) 2012--2015 by The University of Queensland	\\
 \url{http://www.uq.edu.au}				\\
 Primary Business: Queensland, Australia			\\
 Licensed under the Open Software License version 3.0	\\
diff --git a/doc/inversion/verinfo.tex b/doc/inversion/verinfo.tex
new file mode 100644
index 0000000..e509a29
--- /dev/null
+++ b/doc/inversion/verinfo.tex
@@ -0,0 +1,7 @@
+
+\newcommand{\relver}{development}
+\newcommand{\reldate}{\today}
+
+
+%\newcommand{\relver}{4.0}
+%\newcommand{\reldate}{\today}
diff --git a/doc/sphinx_api/SConscript b/doc/sphinx_api/SConscript
index bd3864b..0167aa5 100644
--- a/doc/sphinx_api/SConscript
+++ b/doc/sphinx_api/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/sphinx_api/genrst.py b/doc/sphinx_api/genrst.py
index 6b488ea..368eb18 100755
--- a/doc/sphinx_api/genrst.py
+++ b/doc/sphinx_api/genrst.py
@@ -28,10 +28,10 @@ def dumpPackage(mname, ignorelist, modset, banset):
   pack=open(os.path.join(outdir,mname+'.rst'),'w')
   pack.write(mname+' Package\n')
   pack.write('='*len(mname)+'========\n\n')
-  pack.write('.. py:module:: '+mname+'\n\n')
+#  pack.write('.. py:module:: '+mname+'\n\n')
   moddoc = inspect.getdoc(PP)
   if moddoc:
-    pack.write("   "+moddoc.replace("\n\n", "\n").replace("\n", "\n   ") + "\n")
+    pack.write(".. automodule:: %s\n   :synopsis: %s\n"%(mname, "".join(moddoc.replace("\n\n", "\n").replace("\n", " "))))
   #Automodule does not seem to do what we want so we need to drill down
   clist=[]
   flist=[]
@@ -74,14 +74,14 @@ def dumpPackage(mname, ignorelist, modset, banset):
           flist+=[(name, mem)]
         else:
           vlist+=[(name, mem)]
-  pack.write('Classes\n')
+  pack.write('\nClasses\n')
   pack.write('-------\n')
   for (name, mem) in clist:
       pack.write('* `'+name+'`\n')
   pack.write('\n')
   for (name, mem) in clist:
     pack.write('.. autoclass:: '+name+'\n')
-    pack.write('   :members:\n   :undoc-members:\n\n')
+    pack.write('   :members:\n   :undoc-members:\n\n   .. automethod:: __init__\n\n')
   pack.write('\n')
     
   pack.write('Functions\n')
diff --git a/doc/user/Models.tex b/doc/user/Models.tex
index 4158e30..16a5d27 100644
--- a/doc/user/Models.tex
+++ b/doc/user/Models.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/SConscript b/doc/user/SConscript
index 34c008d..c82dc8e 100644
--- a/doc/user/SConscript
+++ b/doc/user/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/doc/user/TutorialPDE.tex b/doc/user/TutorialPDE.tex
index 79d538f..0097376 100644
--- a/doc/user/TutorialPDE.tex
+++ b/doc/user/TutorialPDE.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/appendix.tex b/doc/user/appendix.tex
index 5c09d5f..b9a8c3c 100644
--- a/doc/user/appendix.tex
+++ b/doc/user/appendix.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/changes.tex b/doc/user/changes.tex
index 0f24a49..43c8190 100644
--- a/doc/user/changes.tex
+++ b/doc/user/changes.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/darcyflux.tex b/doc/user/darcyflux.tex
index 7de88c2..7df36e7 100644
--- a/doc/user/darcyflux.tex
+++ b/doc/user/darcyflux.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/diffusion.tex b/doc/user/diffusion.tex
index fc25761..b293f0e 100644
--- a/doc/user/diffusion.tex
+++ b/doc/user/diffusion.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/escript.tex b/doc/user/escript.tex
index 055e3ba..f4c5676 100644
--- a/doc/user/escript.tex
+++ b/doc/user/escript.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/execute.tex b/doc/user/execute.tex
index 8a4b93f..572cc5c 100644
--- a/doc/user/execute.tex
+++ b/doc/user/execute.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/faultsystem.tex b/doc/user/faultsystem.tex
index e33f119..7fb4e96 100644
--- a/doc/user/faultsystem.tex
+++ b/doc/user/faultsystem.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/finley.tex b/doc/user/finley.tex
index c8d7ef2..737d224 100644
--- a/doc/user/finley.tex
+++ b/doc/user/finley.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/finleyelements.tex b/doc/user/finleyelements.tex
index 10a1c0f..51e9bc5 100644
--- a/doc/user/finleyelements.tex
+++ b/doc/user/finleyelements.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/firststep.tex b/doc/user/firststep.tex
index efcd7dd..de5c81a 100644
--- a/doc/user/firststep.tex
+++ b/doc/user/firststep.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/heatedblock.tex b/doc/user/heatedblock.tex
index 4e9fa26..ec708e2 100644
--- a/doc/user/heatedblock.tex
+++ b/doc/user/heatedblock.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/levelset.tex b/doc/user/levelset.tex
index 95acda6..f01d01b 100644
--- a/doc/user/levelset.tex
+++ b/doc/user/levelset.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/levelsetmodel.tex b/doc/user/levelsetmodel.tex
index 307576b..b7ce774 100644
--- a/doc/user/levelsetmodel.tex
+++ b/doc/user/levelsetmodel.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/linearPDE.tex b/doc/user/linearPDE.tex
index 48b767c..9697c91 100644
--- a/doc/user/linearPDE.tex
+++ b/doc/user/linearPDE.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/lumping.tex b/doc/user/lumping.tex
index 81386da..0368947 100644
--- a/doc/user/lumping.tex
+++ b/doc/user/lumping.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/modelframe.tex b/doc/user/modelframe.tex
index e2a04bd..c2cbe53 100644
--- a/doc/user/modelframe.tex
+++ b/doc/user/modelframe.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/nonlinearPDE.tex b/doc/user/nonlinearPDE.tex
index 31d25fd..075e726 100644
--- a/doc/user/nonlinearPDE.tex
+++ b/doc/user/nonlinearPDE.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/notation.tex b/doc/user/notation.tex
index 080ee34..22c71ff 100644
--- a/doc/user/notation.tex
+++ b/doc/user/notation.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/ourrefs.tex b/doc/user/ourrefs.tex
index 522a5eb..e8bf226 100644
--- a/doc/user/ourrefs.tex
+++ b/doc/user/ourrefs.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/py3.tex b/doc/user/py3.tex
index a38ab73..1410c19 100644
--- a/doc/user/py3.tex
+++ b/doc/user/py3.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/pycad.tex b/doc/user/pycad.tex
index c36f56e..69ca436 100644
--- a/doc/user/pycad.tex
+++ b/doc/user/pycad.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/ripley.tex b/doc/user/ripley.tex
index 3f2996d..f346289 100644
--- a/doc/user/ripley.tex
+++ b/doc/user/ripley.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/slip.tex b/doc/user/slip.tex
index 36d9300..fa21af2 100644
--- a/doc/user/slip.tex
+++ b/doc/user/slip.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/speckley.tex b/doc/user/speckley.tex
index f15372b..1663023 100644
--- a/doc/user/speckley.tex
+++ b/doc/user/speckley.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/stokesflow.tex b/doc/user/stokesflow.tex
index 0c6b874..472c572 100644
--- a/doc/user/stokesflow.tex
+++ b/doc/user/stokesflow.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/stokessolver.tex b/doc/user/stokessolver.tex
index ac7bdae..1f2cf74 100644
--- a/doc/user/stokessolver.tex
+++ b/doc/user/stokessolver.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/symbolic.tex b/doc/user/symbolic.tex
index d74e26f..af5c8a1 100644
--- a/doc/user/symbolic.tex
+++ b/doc/user/symbolic.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/user.tex b/doc/user/user.tex
index 0af6dfe..f9d2b8f 100644
--- a/doc/user/user.tex
+++ b/doc/user/user.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
@@ -21,6 +21,7 @@
 \usepackage{upquote} %used to prevent LaTeX from mucking up '
 \usepackage{graphicx, subfigure}
 
+\input{verinfo}
 % \newcommand{\hackscore}{_}
 
 % title, author, etc stuff
@@ -33,8 +34,8 @@ The University of Queensland \\
 Brisbane, Australia \\
 %Email: \email{esys at esscc.uq.edu.au}
 }
-\date{\today}
-\release{4.0}
+\date{\reldate}
+\release{\relver}
 %\release{development}
 
 \makeindex
diff --git a/doc/user/user_defs.tex b/doc/user/user_defs.tex
index 2ac7fb0..7e74e9a 100644
--- a/doc/user/user_defs.tex
+++ b/doc/user/user_defs.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/verinfo.tex b/doc/user/verinfo.tex
new file mode 100644
index 0000000..e509a29
--- /dev/null
+++ b/doc/user/verinfo.tex
@@ -0,0 +1,7 @@
+
+\newcommand{\relver}{development}
+\newcommand{\reldate}{\today}
+
+
+%\newcommand{\relver}{4.0}
+%\newcommand{\reldate}{\today}
diff --git a/doc/user/wave.tex b/doc/user/wave.tex
index 39dc266..0fa06ea 100644
--- a/doc/user/wave.tex
+++ b/doc/user/wave.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/user/weipa.tex b/doc/user/weipa.tex
index 7009a34..b61e8e2 100644
--- a/doc/user/weipa.tex
+++ b/doc/user/weipa.tex
@@ -1,6 +1,6 @@
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Copyright (c) 2003-2014 by University of Queensland
+% Copyright (c) 2003-2015 by The University of Queensland
 % http://www.uq.edu.au
 %
 % Primary Business: Queensland, Australia
diff --git a/doc/verinfo.tex b/doc/verinfo.tex
new file mode 100644
index 0000000..e509a29
--- /dev/null
+++ b/doc/verinfo.tex
@@ -0,0 +1,7 @@
+
+\newcommand{\relver}{development}
+\newcommand{\reldate}{\today}
+
+
+%\newcommand{\relver}{4.0}
+%\newcommand{\reldate}{\today}
diff --git a/downunder/py_src/SConscript b/downunder/py_src/SConscript
index a4ee061..5d0ad21 100644
--- a/downunder/py_src/SConscript
+++ b/downunder/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -19,13 +19,16 @@ local_env = env.Clone()
 
 # get the source file names
 sources = Glob('*.py')
+fmsources = Glob('forwardmodels/*.py')
 
 # compile
 pyc = local_env.PyCompile(sources)
+fmpyc = local_env.PyCompile(fmsources)
 
 # install
 py_inst = local_env.Install(local_env['pyinstall']+'/downunder', pyc)
-env.Alias('install_downunder_py', py_inst)
+fmpy_inst = local_env.Install(local_env['pyinstall']+'/downunder/forwardmodels', fmpyc)
+env.Alias('install_downunder_py', [py_inst, fmpy_inst])
 
 # configure unit tests
 local_env.SConscript(dirs = ['#/downunder/test/python'], variant_dir='$BUILD_DIR/$PLATFORM/downunder/test/python', duplicate=0)
diff --git a/downunder/py_src/__init__.py b/downunder/py_src/__init__.py
index 9776e8a..01aeab7 100644
--- a/downunder/py_src/__init__.py
+++ b/downunder/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Data inversion module built on escript"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -28,10 +28,12 @@ from .datasources import *
 from .domainbuilder import *
 from .forwardmodels import *
 from .inversioncostfunctions import *
+from .splitinversioncostfunctions import *
 from .inversions import *
 from .mappings import *
 from .minimizers import *
 from .regularizations import *
+from .splitregularizations import *
 from .coordinates import *
 from .seismic import *
 from .domaingeneratordcresistivity import *
diff --git a/downunder/py_src/coordinates.py b/downunder/py_src/coordinates.py
index 12d0483..28e246f 100644
--- a/downunder/py_src/coordinates.py
+++ b/downunder/py_src/coordinates.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Functions to deal with coordinate systems"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/py_src/costfunctions.py b/downunder/py_src/costfunctions.py
index 12e9b7c..e19d90a 100644
--- a/downunder/py_src/costfunctions.py
+++ b/downunder/py_src/costfunctions.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """General cost functions for minimization"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/py_src/datasources.py b/downunder/py_src/datasources.py
index fd140d5..6b2e882 100644
--- a/downunder/py_src/datasources.py
+++ b/downunder/py_src/datasources.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Data readers/providers for inversions"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/py_src/dcresistivityforwardmodeling.py b/downunder/py_src/dcresistivityforwardmodeling.py
index 10ce709..8bf160e 100644
--- a/downunder/py_src/dcresistivityforwardmodeling.py
+++ b/downunder/py_src/dcresistivityforwardmodeling.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-from esys.escript import Data, kronecker, whereZero,inf,sup,ContinuousFunction,grad,Function,Lsup
+from esys.escript import Data, kronecker, whereZero,inf,sup,ContinuousFunction,grad,Function,Lsup, Scalar, DiracDeltaFunctions
 from esys.escript.linearPDEs import LinearPDE
 from esys.escript.pdetools import Locator
 from math import pi
@@ -59,6 +59,7 @@ class DcResistivityForward(object):
         for i in range(self.numElectrodes):
             if (self.electrodes[i][0] < xDim[0] or self.electrodes[i][0] > xDim[1]
                     or self.electrodes[i][1] < yDim[0] or self.electrodes[i][1] > yDim[1]):
+                print (self.electrodes[i])
                 raise ValueError("Electrode setup extents past domain dimentions")
     def getElectrodes(self):
         """
@@ -104,6 +105,10 @@ class SchlumbergerSurvey(DcResistivityForward):
         self.numElectrodes=numElectrodes
         self.delPhiPrimaryList=[]
         self.delPhiSecondaryList=[]
+        self.samples=[]
+        self.sources=[]
+        self.electrodeDict={}
+        self.electrodeTags=[]
         if (numElectrodes < 4):
             raise ValueError("numElectrodes must atleast 4 for schlumberger surveys")
         if n > ((numElectrodes-2)//2):
@@ -115,13 +120,75 @@ class SchlumbergerSurvey(DcResistivityForward):
             start.append(midPoint[1] - (((numElectrodes-1)*a)/2. * directionVector[1]))
             for i in range(numElectrodes):
                 electrodes.append([start[0]+(directionVector[0]*i*a), start[1]+(directionVector[1]*i*a),0])
+                self.electrodeTags.append("e%d"%i)
+                self.electrodeDict[self.electrodeTags[i]]=electrodes[i]
         else:
             raise NotImplementedError("2d forward model is not yet implemented please provide a 2 component directionVector for a 3d survey")
         self.electrodes=electrodes
         self.checkBounds()
 
+    def getPotentialNumeric(self):
+        """
+        Returns 3 list each made up of a number of list containing primary, secondary and total
+        potentials diferences. Each of the lists contain a list for each value of n.
+        """
+        primCon=self.primaryConductivity
+        coords=self.domain.getX()
+        tol=1e-8
+        pde=LinearPDE(self.domain, numEquations=1)
+        pde.getSolverOptions().setTolerance(tol)
+        pde.setSymmetryOn()
+        primaryPde=LinearPDE(self.domain, numEquations=1)
+        primaryPde.getSolverOptions().setTolerance(tol)
+        primaryPde.setSymmetryOn()
+        DIM=self.domain.getDim()
+        x=self.domain.getX()
+        q=whereZero(x[DIM-1]-inf(x[DIM-1]))
+        for i in xrange(DIM-1):
+            xi=x[i]
+            q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
+        A = self.secondaryConductivity * kronecker(self.domain)
+        APrimary = self.primaryConductivity * kronecker(self.domain)
+        pde.setValue(A=A,q=q)
+        primaryPde.setValue(A=APrimary,q=q)
 
-    def getPotential(self):
+        delPhiSecondaryList = []
+        delPhiPrimaryList = []
+        delPhiTotalList = []
+        for i in range(1,self.n+1): # 1 to n
+            maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey
+            delPhiSecondary = []
+            delPhiPrimary = []
+            delPhiTotal = []
+            for j in range(maxR):
+                y_dirac=Scalar(0,DiracDeltaFunctions(self.domain))
+                y_dirac.setTaggedValue(self.electrodeTags[j],self.current)
+                y_dirac.setTaggedValue(self.electrodeTags[j + ((2*i) + 1)],-self.current)
+                self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]])
+                primaryPde.setValue(y_dirac=y_dirac)
+                numericPrimaryPot = primaryPde.getSolution()
+                X=(primCon-self.secondaryConductivity) * grad(numericPrimaryPot)
+                pde.setValue(X=X)
+                u=pde.getSolution()
+                loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]])
+                self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]])
+                valPrimary=loc.getValue(numericPrimaryPot)
+                valSecondary=loc.getValue(u)
+                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
+                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
+                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
+            delPhiPrimaryList.append(delPhiPrimary)
+            delPhiSecondaryList.append(delPhiSecondary)
+            delPhiTotalList.append(delPhiTotal)
+
+        self.delPhiPrimaryList=delPhiPrimaryList
+        self.delPhiSecondaryList=delPhiSecondaryList
+        self.delPhiTotalList = delPhiTotalList
+        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
+
+
+
+    def getPotentialAnalytic(self):
         """
         Returns 3 list each made up of a number of list containing primary, secondary and total
         potentials diferences. Each of the lists contain a list for each value of n.
@@ -161,8 +228,10 @@ class SchlumbergerSurvey(DcResistivityForward):
                 analyticRsTwo[1]=(coords[1]-self.electrodes[j + ((2*i) + 1)][1])
                 analyticRsTwo[2]=(coords[2])
                 rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5
+                self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]])
                 rsMagOne+=(whereZero(rsMagOne)*0.0000001)
                 rsMagTwo+=(whereZero(rsMagTwo)*0.0000001)
+                
                 analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo))
                 analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5
                 analyticRsOnePower = analyticRsOnePower+(whereZero(analyticRsOnePower)*0.0001)
@@ -177,10 +246,11 @@ class SchlumbergerSurvey(DcResistivityForward):
                 pde.setValue(X=X)
                 u=pde.getSolution()
                 loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]])
+                self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]])
                 valPrimary=loc.getValue(analyticPrimaryPot)
                 valSecondary=loc.getValue(u)
-                delPhiPrimary.append(valPrimary[0]-valPrimary[1])
-                delPhiSecondary.append(valSecondary[0]-valSecondary[1])
+                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
+                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                 delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
             delPhiPrimaryList.append(delPhiPrimary)
             delPhiSecondaryList.append(delPhiSecondary)
@@ -191,52 +261,33 @@ class SchlumbergerSurvey(DcResistivityForward):
         self.delPhiTotalList = delPhiTotalList
         return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
 
-    def getApparentResistivityPrimary(self):
+    def getApparentResistivity(self, delPhiList):
         resistivityList = []
         n=self.n
         if (self.delPhiPrimaryList==[]):
             self.getPotential()
 
         nCount=1
-        for i in self.delPhiPrimaryList:
-            resistivity=[]
-            for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1))*pi*self.a)
-            nCount=nCount+1
-            resistivityList.append(resistivity)
-        return resistivityList
-
-
-    def getApparentResistivitySecondary(self):
-        resistivityList = []
-        n=self.n
-        if (self.delPhiSecondaryList==[]):
-            self.getPotential()
-
-        nCount=1
-        for i in self.delPhiSecondaryList:
+        for i in delPhiList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1))*pi*self.a)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1))*pi*self.a)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
 
-    def getApparentResistivityTotal(self):
-        resistivityList = []
-        n=self.n
-        if (self.delPhiSecondaryList==[]):
-            self.getPotential()
-
-        nCount=1
-        for i in self.delPhiTotalList:
-            resistivity=[]
-            for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1))*pi*self.a)
-            nCount=nCount+1
-            resistivityList.append(resistivity)
-        return resistivityList
+    def getSourcesSamples(self):
+        """
+        return a list of tuples of sample locations followed by a list of tuples
+        of source locations.
+        """
+        return self.samples, self.sources
 
+    def getElectrodeDict(self):
+        """
+        retuns the electrode dictionary
+        """
+        return self.electrodeDict
 
 class WennerSurvey(DcResistivityForward):
     """
@@ -351,8 +402,8 @@ class WennerSurvey(DcResistivityForward):
                 loc=Locator(self.domain,[self.electrodes[i+1],self.electrodes[i+2]])
                 valPrimary=loc.getValue(analyticPrimaryPot)
                 valSecondary=loc.getValue(u)
-                delPhiPrimary.append(valPrimary[0]-valPrimary[1])
-                delPhiSecondary.append(valSecondary[0]-valSecondary[1])
+                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
+                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                 delPhiTotal.append(delPhiPrimary[i]+delPhiSecondary[i])
         else:
             raise NotImplementedError("2d forward model is not yet implemented")
@@ -369,7 +420,7 @@ class WennerSurvey(DcResistivityForward):
             self.getPotential()
 
         for i in self.delPhiPrimary:
-            resistivity.append((i/self.current)*2*pi*self.a)
+            resistivity.append((-i/self.current)*2*pi*self.a)
 
         return resistivity
 
@@ -381,7 +432,7 @@ class WennerSurvey(DcResistivityForward):
             self.getPotential()
 
         for i in self.delPhiSecondary:
-            resistivity.append((i/self.current)*2*pi*self.a)
+            resistivity.append((-i/self.current)*2*pi*self.a)
 
         return resistivity
 
@@ -392,7 +443,7 @@ class WennerSurvey(DcResistivityForward):
                 self.getPotential()
 
             for i in range(len(self.delPhiSecondary)):
-                resistivity.append(((self.delPhiSecondary[i]+self.delPhiPrimary[i])/self.current)*2*pi*self.a)
+                resistivity.append((-(self.delPhiSecondary[i]+self.delPhiPrimary[i])/self.current)*2*pi*self.a)
 
             return resistivity
 
@@ -511,8 +562,8 @@ class DipoleDipoleSurvey(DcResistivityForward):
                 loc=Locator(self.domain,[self.electrodes[1+j+i],self.electrodes[j+i+2]])
                 valPrimary=loc.getValue(analyticPrimaryPot)
                 valSecondary=loc.getValue(u)
-                delPhiPrimary.append(valPrimary[0]-valPrimary[1])
-                delPhiSecondary.append(valSecondary[0]-valSecondary[1])
+                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
+                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                 delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
             delPhiPrimaryList.append(delPhiPrimary)
             delPhiSecondaryList.append(delPhiSecondary)
@@ -533,7 +584,7 @@ class DipoleDipoleSurvey(DcResistivityForward):
         for i in self.delPhiPrimaryList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1)*(nCount+2))*pi*self.a)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1)*(nCount+2))*pi*self.a)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
@@ -549,7 +600,7 @@ class DipoleDipoleSurvey(DcResistivityForward):
         for i in self.delPhiSecondaryList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1)*(nCount+2))*pi*self.a)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1)*(nCount+2))*pi*self.a)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
@@ -564,7 +615,7 @@ class DipoleDipoleSurvey(DcResistivityForward):
         for i in self.delPhiTotalList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1)*(nCount+2))*pi*self.a)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1)*(nCount+2))*pi*self.a)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
@@ -675,8 +726,8 @@ class PoleDipoleSurvey(DcResistivityForward):
                 loc=Locator(self.domain,[self.electrodes[i+j],self.electrodes[i+j+1]])
                 valPrimary=loc.getValue(analyticPrimaryPot)
                 valSecondary=loc.getValue(u)
-                delPhiPrimary.append(valPrimary[0]-valPrimary[1])
-                delPhiSecondary.append(valSecondary[0]-valSecondary[1])
+                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
+                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                 delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
 
             delPhiPrimaryList.append(delPhiPrimary)
@@ -702,7 +753,7 @@ class PoleDipoleSurvey(DcResistivityForward):
         for i in self.delPhiPrimaryList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1))*pi*self.a*2)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1))*pi*self.a*2)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
@@ -718,7 +769,7 @@ class PoleDipoleSurvey(DcResistivityForward):
         for i in self.delPhiSecondaryList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1))*pi*self.a*2)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1))*pi*self.a*2)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
@@ -733,7 +784,7 @@ class PoleDipoleSurvey(DcResistivityForward):
         for i in self.delPhiTotalList:
             resistivity=[]
             for j in i:
-                resistivity.append((j/self.current)*(nCount*(nCount+1))*pi*self.a*2)
+                resistivity.append((-j/self.current)*(nCount*(nCount+1))*pi*self.a*2)
             nCount=nCount+1
             resistivityList.append(resistivity)
         return resistivityList
diff --git a/downunder/py_src/domainbuilder.py b/downunder/py_src/domainbuilder.py
index ad871f6..9b37da4 100644
--- a/downunder/py_src/domainbuilder.py
+++ b/downunder/py_src/domainbuilder.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Domain construction from survey data for inversions"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/py_src/domaingeneratordcresistivity.py b/downunder/py_src/domaingeneratordcresistivity.py
index cbc50c7..4f5a876 100644
--- a/downunder/py_src/domaingeneratordcresistivity.py
+++ b/downunder/py_src/domaingeneratordcresistivity.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -33,13 +33,12 @@ class DCResDomGenerator(object):
     This class is used to generate an escript domain which is suitable for
     solving dc resistivity problems
     """
-    def __init__(self, extents, electrodeDict, lc=0.1, tmpDir=None, prism=None, bufferThickness=None):
+    def __init__(self, extents, electrodeLst, lc=0.1, tmpDir=None, prism=None, bufferThickness=None):
         """
         :param extents: x,y,z extents of the domain
         :type extents: list or tuple, len should=3
-        :param electrodeDict: dictionary to hold coords and characteristic length of
-        points to be used as electrodes.
-        :type electrodeDict: dictionary
+        :param electrodeLst: A list of tuples of the form (tag,coords) for each electrode
+        :type electrodeLst: list of tuples
         :param lc:
         :type float
         :param prism: provide start point,extents and a extrude depth for a cubic prism
@@ -52,8 +51,13 @@ class DCResDomGenerator(object):
             self.__extents=extents
         else:
             raise ValueError("extents should be of length 3 or 4")
+        for i in electrodeLst:
+            if len(electrodeLst[i]) != 4:
+                raise ValueError("currently only 3d domains are supported electrodeLst elements must be of length 4)")
+        if not isinstance(electrodeLst,list):
+            raise TypeError("electrodeLst must be a list of tuples of the form (tag,coords) for each electrode")
         self.__extentLen = len(self.__extents)
-        self.__electrodeDict=electrodeDict
+        self.__electrodeLst=electrodeLst
         self.__lc=lc
         self.__scriptString=""
         self.__pntList=""
@@ -62,25 +66,26 @@ class DCResDomGenerator(object):
         self.__points=[]
         self.__tmpDir=tmpDir
         self.__bufferThickness=bufferThickness
-        # logger.debug(electrodeDict)
+        self.filename=""
+        # logger.debug(electrodeLst)
 
-        for i in electrodeDict:
+        for i in electrodeLst:
             self.__tags.append(i)
-            self.__points.append(electrodeDict[i][:-1])
+            self.__points.append(electrodeLst[i][:-1])
 
-    def generateScriptFile(self, interfaces=None):
+    def generateScriptFile(self, fieldSize, interfaces=None):
         fd, filename = tempfile.mkstemp(suffix=".geo", dir=self.__tmpDir)
         os.close(fd)
         
         if interfaces is None:
-            self.generateScriptString()
+            self.generateScriptString(fieldSize)
         else:
-            self.generateLayedScriptString(interfaces)
+            self.generateLayedScriptString(interfaces, fieldSize)
         
         open(filename, "w").write(self.__scriptString)
         return filename
 
-    def generateScriptString(self):
+    def generateScriptString(self,fieldSize):
         pntCount=5
         leftStr ="-out0[2],"
         rightStr="-out0[4],"
@@ -90,10 +95,10 @@ class DCResDomGenerator(object):
 
         if not self.__bufferThickness == None:
             out.append("lc=%f;\n"%self.__lc)
-            out.append("Point(1)={%f, %f, 0, lc};\n"%(-self.__bufferThickness , -self.__bufferThickness))
-            out.append("Point(2)={%f, %f, 0, lc};\n"%( (self.__extents[0]+self.__bufferThickness), -self.__bufferThickness))
-            out.append("Point(3)={%f, %f, 0, lc};\n"%( (self.__extents[0]+self.__bufferThickness), (self.__extents[1]+self.__bufferThickness)))
-            out.append("Point(4)={%f, %f, 0, lc};\n"%( -self.__bufferThickness, (self.__extents[1]+self.__bufferThickness)))
+            out.append("Point(1)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.-self.__bufferThickness) , (-self.__extents[1]/2.-self.__bufferThickness)))
+            out.append("Point(2)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.+self.__bufferThickness)  , (-self.__extents[1]/2.-self.__bufferThickness)))
+            out.append("Point(3)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.+self.__bufferThickness)  , (self.__extents[1]/2.+self.__bufferThickness)))
+            out.append("Point(4)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.-self.__bufferThickness) , (self.__extents[1]/2.+self.__bufferThickness)))
             out.append("Line(1) = {1,2} ;\n")
             out.append("Line(2) = {3,2} ;\n")
             out.append("Line(3) = {3,4} ;\n")
@@ -114,8 +119,8 @@ class DCResDomGenerator(object):
                 out.append("Line Loop(6) = {8,5,-6,7} ;\n")
                 out.append("Plane Surface(7) = {6} ; \n")
 
-            for i in self.__electrodeDict:
-                pntInfo=self.__electrodeDict[i]
+            for i in self.__electrodeLst:
+                pntInfo=i[1]
                 out.append("Point(%d)={%f,%f,%f,%f};\n"%(pntCount,pntInfo[0],pntInfo[1],pntInfo[2],pntInfo[3]))
                 pntCount+=1
             out.append("out0[]=Extrude {0, 0, -%f} { Surface {6};};\n"%(self.__extents[2]+self.__bufferThickness))
@@ -131,10 +136,10 @@ class DCResDomGenerator(object):
 
         else:
             out.append("lc=%f;\n"%self.__lc)
-            out.append("Point(1)={0,-1,0,lc};\n")
-            out.append("Point(2)={%f,-1,0,lc};\n"%self.__extents[0])
-            out.append("Point(3)={%f,%f,0,lc};\n"%(self.__extents[0],(self.__extents[1]+1)))
-            out.append("Point(4)={0,%f,0,lc};\n"%(self.__extents[1]+1))
+            out.append("Point(1)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.) , (-self.__extents[1]/2.)))
+            out.append("Point(2)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.)  , (-self.__extents[1]/2.)))
+            out.append("Point(3)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.)  , (self.__extents[1]/2.)))
+            out.append("Point(4)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.) , (self.__extents[1]/2.)))
             out.append("Line(1) = {1,2} ;\n")
             out.append("Line(2) = {3,2} ;\n")
             out.append("Line(3) = {3,4} ;\n")
@@ -158,8 +163,8 @@ class DCResDomGenerator(object):
                 out.append("Line Loop(6) = {8,5,-6,7} ;\n")
                 out.append("Plane Surface(7) = {6} ; \n")
 
-            for i in self.__electrodeDict:
-                pntInfo=self.__electrodeDict[i]
+            for i in self.__electrodeLst:
+                pntInfo=i[1]
                 out.append("Point(%d)={%f,%f,%f,%f};\n"%(pntCount,pntInfo[0],pntInfo[1],pntInfo[2],pntInfo[3]))
                 pntCount+=1
 
@@ -184,10 +189,10 @@ class DCResDomGenerator(object):
             out.append("Field[1] = Box;\n")
             out.append("Field[1].VIn=lc;\n")
             out.append("Field[1].VOut=5*lc;\n")
-            out.append("Field[1].XMax=%f;\n"%self.__extents[0])
-            out.append("Field[1].XMin=0;\n")
-            out.append("Field[1].YMax=%f;\n"%self.__extents[1])
-            out.append("Field[1].YMin=0;\n")
+            out.append("Field[1].XMax=%f;\n"%(self.__extents[0]/2.))
+            out.append("Field[1].XMin=%f;\n"%(-self.__extents[0]/2.))
+            out.append("Field[1].YMax=%f;\n"%(self.__extents[1]/2.))
+            out.append("Field[1].YMin=%f;\n"%(-self.__extents[1]/2.))
             out.append("Field[1].ZMax=0;\n")
             out.append("Field[1].ZMin=-%f;\n"%self.__extents[2])
             out.append("Field[2] = Attractor;\n")
@@ -196,15 +201,19 @@ class DCResDomGenerator(object):
             out.append("Field[3].IField = 2;\n")
             out.append("Field[3].LcMin = lc / 5;\n")
             out.append("Field[3].LcMax = 100*lc;\n") # this value is so high because It should not play a role in field 4
-            out.append("Field[3].DistMin = 50;\n")
-            out.append("Field[3].DistMax = 100;\n")
+            if fieldSize == None:
+                out.append("Field[3].DistMin = 50.0;\n")
+                out.append("Field[3].DistMax = 100.0;\n")
+            else:
+                out.append("Field[3].DistMin = %g;\n"%fieldSize[0])
+                out.append("Field[3].DistMax = %g;\n"%fieldSize[1])
             out.append("Field[4] = Min;\n")
             out.append("Field[4].FieldsList = {1, 3};\n")
             out.append("Background Field = 4;\n")
             out.append("Mesh.CharacteristicLengthExtendFromBoundary = 0;\n")
         self.__scriptString = "".join(out)
 
-    def generateLayedScriptString(self, interfaces):
+    def generateLayedScriptString(self, interfaces, fieldSize):
         pntCount=5
         leftStr ="-out0[2],"
         rightStr="-out0[4],"
@@ -215,18 +224,18 @@ class DCResDomGenerator(object):
 
         if not self.__bufferThickness == None:
             out.append("lc=%f;\n"%self.__lc)
-            out.append("Point(1)={%f, %f, 0, lc};\n"%(-self.__bufferThickness , -self.__bufferThickness))
-            out.append("Point(2)={%f, %f, 0, lc};\n"%( (self.__extents[0]+self.__bufferThickness), -self.__bufferThickness))
-            out.append("Point(3)={%f, %f, 0, lc};\n"%( (self.__extents[0]+self.__bufferThickness), (self.__extents[1]+ self.__bufferThickness)))
-            out.append("Point(4)={%f, %f, 0, lc};\n"%(-self.__bufferThickness, (self.__extents[1]+self.__bufferThickness)))
+            out.append("Point(1)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.-self.__bufferThickness) , (-self.__extents[1]/2.-self.__bufferThickness)))
+            out.append("Point(2)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.+self.__bufferThickness)  , (-self.__extents[1]/2.-self.__bufferThickness)))
+            out.append("Point(3)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.+self.__bufferThickness)  , (self.__extents[1]/2.+self.__bufferThickness)))
+            out.append("Point(4)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.-self.__bufferThickness) , (self.__extents[1]/2.+self.__bufferThickness)))
             out.append("Line(1) = {1,2} ;\n")
             out.append("Line(2) = {3,2} ;\n")
             out.append("Line(3) = {3,4} ;\n")
             out.append("Line(4) = {4,1} ;\n")
             out.append("Line Loop(5) = {4,1,-2,3} ; \n")
             out.append("Plane Surface(6) = {5} ; \n")
-            for i in self.__electrodeDict:
-                pntInfo=self.__electrodeDict[i]
+            for i in self.__electrodeLst:
+                pntInfo=i[1]
                 out.append("Point(%d)={%f,%f,%f,%f};\n"%(pntCount,pntInfo[0],pntInfo[1],pntInfo[2],pntInfo[3]))
                 pntCount+=1
             #out.append("out[]=Extrude {0, 0, -%f} { Surface {6};};\n"%self.__bufferThickness)
@@ -250,25 +259,25 @@ class DCResDomGenerator(object):
                 backStr+= "-out%d[3],"%i
             i+=1
             out.append("out%d[]=Extrude {0, 0, -%f} { Surface {out%d[0]};};\n"%(i,self.__bufferThickness,i-1))
-            out.append("Physical Volume(\"volume-%d\") = {%d} ;\n"%(i+1,i+2))
+            out.append("Physical Volume(\"volume-%d\") = {%d} ;\n"%(i+1,i+1))
             leftStr+= "-out%d[2],"%i
             rightStr+="-out%d[4],"%i
             frontStr+="-out%d[5],"%i
             backStr+= "-out%d[3],"%i
         else:
             out.append("lc=%f;\n"%self.__lc)
-            out.append("Point(1)={0,-1,0,lc};\n")
-            out.append("Point(2)={%f,-1,0,lc};\n"%self.__extents[0])
-            out.append("Point(3)={%f,%f,0,lc};\n"%(self.__extents[0],(self.__extents[1]+1)))
-            out.append("Point(4)={0,%f,0,lc};\n"%(self.__extents[1]+1))
+            out.append("Point(1)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.) , (-self.__extents[1]/2.)))
+            out.append("Point(2)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.)  , (-self.__extents[1]/2.)))
+            out.append("Point(3)={%f, %f, 0, lc};\n"%( (self.__extents[0]/2.)  , (self.__extents[1]/2.)))
+            out.append("Point(4)={%f, %f, 0, lc};\n"%( (-self.__extents[0]/2.) , (self.__extents[1]/2.)))
             out.append("Line(1) = {1,2} ;\n")
             out.append("Line(2) = {3,2} ;\n")
             out.append("Line(3) = {3,4} ;\n")
             out.append("Line(4) = {4,1} ;\n")
             out.append("Line Loop(5) = {4,1,-2,3} ; \n")
             out.append("Plane Surface(6) = {5} ; \n")
-            for i in self.__electrodeDict:
-                pntInfo=self.__electrodeDict[i]
+            for i in self.__electrodeLst:
+                pntInfo=i[1]
                 out.append("Point(%d)={%f,%f,%f,%f};\n"%(pntCount,pntInfo[0],pntInfo[1],pntInfo[2],pntInfo[3]))
                 pntCount+=1
             self.__pntList=str([i for i in range(5,pntCount)])[1:-1]
@@ -285,20 +294,20 @@ class DCResDomGenerator(object):
                 backStr+= "-out%d[3],"%i
 
 
-        out.append("Physical Surface(\"Top\") = { -6 };\n")
-        out.append("Physical Surface(\"Bottom\") = { -out%d[0] };\n"%i)
-        out.append("Physical Surface(\"Left\") = { %s };\n"%leftStr[:-1])
-        out.append("Physical Surface(\"Right\") = { %s };\n"%rightStr[:-1])
-        out.append("Physical Surface(\"Front\") = { %s };\n"%frontStr[:-1])
-        out.append("Physical Surface(\"Back\") = { %s };\n"%backStr[:-1])
+        # out.append("Physical Surface(\"Top\") = { -6 };\n")
+        # out.append("Physical Surface(\"Bottom\") = { -out%d[0] };\n"%i)
+        # out.append("Physical Surface(\"Left\") = { %s };\n"%leftStr[:-1])
+        # out.append("Physical Surface(\"Right\") = { %s };\n"%rightStr[:-1])
+        # out.append("Physical Surface(\"Front\") = { %s };\n"%frontStr[:-1])
+        # out.append("Physical Surface(\"Back\") = { %s };\n"%backStr[:-1])
         if not self.__bufferThickness == None:
             out.append("Field[1] = Box;\n")
             out.append("Field[1].VIn=lc;\n")
             out.append("Field[1].VOut=5*lc;\n")
-            out.append("Field[1].XMax=%f;\n"%self.__extents[0])
-            out.append("Field[1].XMin=0;\n")
-            out.append("Field[1].YMax=%f;\n"%self.__extents[1])
-            out.append("Field[1].YMin=0;\n")
+            out.append("Field[1].XMax=%f;\n"%(self.__extents[0]/2.))
+            out.append("Field[1].XMin=%f;\n"%(-self.__extents[0]/2.))
+            out.append("Field[1].YMax=%f;\n"%(self.__extents[1]/2.))
+            out.append("Field[1].YMin=%f;\n"%(-self.__extents[1]/2.))
             out.append("Field[1].ZMax=0;\n")
             out.append("Field[1].ZMin=-%f;\n"%extentCount)
             out.append("Field[2] = Attractor;\n")
@@ -307,8 +316,13 @@ class DCResDomGenerator(object):
             out.append("Field[3].IField = 2;\n")
             out.append("Field[3].LcMin = lc / 5;\n")
             out.append("Field[3].LcMax = 100*lc;\n")
-            out.append("Field[3].DistMin = 50;\n")
-            out.append("Field[3].DistMax = 100;\n")
+            if fieldSize == None:
+                out.append("Field[3].DistMin = 50.0;\n")
+                out.append("Field[3].DistMax = 100.0;\n")
+            else:
+                out.append("Field[3].DistMin = %g;\n"%fieldSize[0])
+                out.append("Field[3].DistMax = %g;\n"%fieldSize[1])
+
             out.append("Field[4] = Min;\n")
             out.append("Field[4].FieldsList = {1, 3};\n")
             out.append("Background Field = 4;\n")
@@ -316,7 +330,7 @@ class DCResDomGenerator(object):
 
         self.__scriptString = "".join(out)
 
-    def getDom(self, mshName=None, interfaces=None):
+    def getDom(self, fieldSize=None, mshName=None, interfaces=None, reUse=False):
         """
         Generates the domain.
         :param interfaces: Specify a list of interfaces for a layered model.
@@ -324,9 +338,13 @@ class DCResDomGenerator(object):
                            will be tagged iteratively from volume-0 to
                            volume-(n-1).
         :type interfaces: list
+        :param reUse: should the msh be reused or should a new file be generated
+        :type reUse: bool
         """
 
-        if (mshName is not None and os.path.isfile(mshName)):
+        filename = "" # won't be used by non-0 ranks
+        self.filename=filename
+        if (mshName is not None and os.path.isfile(mshName) and reUse==True):
             if mshName[-4:]=='.msh':
                 dom=ReadGmsh(mshName, 3, diracTags=self.__tags, diracPoints=self.__points)
             elif mshName[-4:]=='.fly':
@@ -336,17 +354,20 @@ class DCResDomGenerator(object):
         # early exit so we don't even create files if we don't have to
         if not HAVE_GMSH:
             raise RuntimeError("gmsh is not available to build meshfiles")
-
-        filename = "" # won't be used by non-0 ranks
+        
         if getMPIRankWorld() == 0:
-            filename = self.generateScriptFile(interfaces)
+            filename = self.generateScriptFile(fieldSize, interfaces=interfaces)
+            self.filename = filename
         verbosity = 3
         if mshName is None:
             mshName = filename[:-4]+".msh"
         else:
             mshName = mshName[:-4]+".msh"
 
-        gmshGeo2Msh(filename, mshName, 3, 1, verbosity)
+        if gmshGeo2Msh(filename, mshName, 3, 1, verbosity)!=0:
+            raise RuntimeError("Call out to gmsh failed")
         dom=ReadGmsh(mshName, 3, diracTags=self.__tags, diracPoints=self.__points)
         return dom
 
+    def getFileName(self):
+        return self.filename
diff --git a/downunder/py_src/forwardmodels.py b/downunder/py_src/forwardmodels.py
deleted file mode 100644
index 0bc074b..0000000
--- a/downunder/py_src/forwardmodels.py
+++ /dev/null
@@ -1,1571 +0,0 @@
-from __future__ import print_function
-from __future__ import division
-##############################################################################
-#
-# Copyright (c) 2003-2014 by University of Queensland
-# http://www.uq.edu.au
-#
-# Primary Business: Queensland, Australia
-# Licensed under the Open Software License version 3.0
-# http://www.opensource.org/licenses/osl-3.0.php
-#
-# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-# Development 2012-2013 by School of Earth Sciences
-# Development from 2014 by Centre for Geoscience Computing (GeoComp)
-#
-##############################################################################
-
-"""Collection of forward models that define the inversion problem"""
-
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
-http://www.uq.edu.au
-Primary Business: Queensland, Australia"""
-__license__="""Licensed under the Open Software License version 3.0
-http://www.opensource.org/licenses/osl-3.0.php"""
-__url__="https://launchpad.net/escript-finley"
-
-__all__ = ['ForwardModel','ForwardModelWithPotential','GravityModel','MagneticModel', 'SelfDemagnetizationModel', 'AcousticWaveForm', 'MT2DModelTEMode','DcRes', 'IsostaticPressure', 'Subsidence']
-
-
-from esys.escript import unitsSI as U
-from esys.escript.pdetools import Locator
-from esys.escript import Data, Vector, Scalar, Function, DiracDeltaFunctions, FunctionOnBoundary, Solution, length, exp
-from esys.escript.linearPDEs import LinearSinglePDE, LinearPDESystem, LinearPDE, SolverOptions
-from .coordinates import makeTranformation
-from esys.escript.util import *
-from math import pi as PI
-from esys.weipa import saveSilo
-import numpy as np
-
-try:
-    xrange
-except NameError:
-    xrange = range
-
-class ForwardModel(object):
-    """
-    An abstract forward model that can be plugged into a cost function.
-    Subclasses need to implement `getDefect()`, `getGradient()`, and possibly
-    `getArguments()` and 'getCoordinateTransformation'.
-    """
-    def __init__(self):
-        pass
-
-    def getArguments(self, x):
-        return ()
-
-    def getDefect(self, x, *args):
-        raise NotImplementedError
-
-    def getGradient(self, x, *args):
-        raise NotImplementedError
-
-    def getCoordinateTransformation(self):
-        return None
-
-
-class ForwardModelWithPotential(ForwardModel):
-    """
-    Base class for a forward model using a potential such as magnetic or
-    gravity. It defines a cost function:
-
-        defect = 1/2 sum_s integrate( ( weight_i[s] * ( r_i - data_i[s] ) ) ** 2 )
-
-    where s runs over the survey, weight_i are weighting factors, data_i are
-    the data, and r_i are the results produced by the forward model.
-    It is assumed that the forward model is produced through postprocessing
-    of the solution of a potential PDE.
-    """
-    def __init__(self, domain, w, data,  coordinates=None,
-                                 fixPotentialAtBottom=False,
-                                 tol=1e-8):
-        """
-        initializes a new forward model with potential.
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param w: data weighting factors
-        :type w: ``Vector`` or list of ``Vector``
-        :param data: data
-        :type data: ``Vector`` or list of ``Vector``
-        :param coordinates: defines coordinate system to be used
-        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        :param fixPotentialAtBottom: if true potential is fixed to zero at the bottom of the domain
-                                     in addition to the top.
-        :type fixPotentialAtBottom: ``bool``
-        """
-        super(ForwardModelWithPotential, self).__init__()
-        self.__domain = domain
-        self.__trafo=makeTranformation(domain, coordinates)
-
-        try:
-            n=len(w)
-            m=len(data)
-            if not m == n:
-                raise ValueError("Length of weight and data must be the same.")
-            self.__weight = w
-            self.__data = data
-        except TypeError:
-            self.__weight = [w]
-            self.__data = [data]
-
-        BX = boundingBox(domain)
-        DIM = domain.getDim()
-        x = domain.getX()
-        self.__pde=LinearSinglePDE(domain)
-        self.__pde.getSolverOptions().setTolerance(tol)
-        self.__pde.setSymmetryOn()
-        z=x[DIM-1]
-        q0=whereZero(z-BX[DIM-1][1])
-        if fixPotentialAtBottom: q0+=whereZero(z-BX[DIM-1][0])
-        self.__pde.setValue(q=q0)
-
-        self.edge_lengths=np.asarray(boundingBoxEdgeLengths(domain))
-        self.diameter=1./sqrt(sum(1./self.edge_lengths**2))
-
-        self.__origweight=[]
-        for s in range(len(self.__weight)):
-            # save a copy of the original weights in case of rescaling
-            self.__origweight.append(1.*self.__weight[s])
-
-        if not self.__trafo.isCartesian():
-            fd=1./self.__trafo.getScalingFactors()
-            fw=self.__trafo.getScalingFactors()*sqrt(self.__trafo.getVolumeFactor())
-            for s in range(len(self.__weight)):
-                self.__weight[s] = fw * self.__weight[s]
-                self.__data[s]   = fd * self.__data[s]
-
-    def _rescaleWeights(self, scale=1., fetch_factor=1.):
-        """
-        rescales the weights such that
-
-        *sum_s integrate( ( weight_i[s] *data_i[s]) (weight_j[s]*1/L_j) * L**2 * fetch_factor )=scale*
-        """
-        if not scale > 0:
-             raise ValueError("Value for scale must be positive.")
-        A=0
-        # copy back original weights before rescaling
-        self.__weight=[1.*ow for ow in self.__origweight]
-
-        for s in range(len(self.__weight)):
-            A += integrate(abs(inner(self.__weight[s], self.__data[s]) * inner(self.__weight[s], 1/self.edge_lengths) * fetch_factor))
-        if A > 0:
-            A=sqrt(scale/A)/self.diameter
-            if not self.__trafo.isCartesian():
-                A*=self.__trafo.getScalingFactors()*sqrt(self.__trafo.getVolumeFactor())
-            for s in range(len(self.__weight)):
-                self.__weight[s]*=A
-        else:
-            raise ValueError("Rescaling of weights failed.")
-
-    def getDomain(self):
-        """
-        Returns the domain of the forward model.
-
-        :rtype: `Domain`
-        """
-        return self.__domain
-
-    def getCoordinateTransformation(self):
-        """
-        returns the coordinate transformation being used
-
-        :rtype: ``CoordinateTransformation``
-        """
-        return self.__trafo
-
-    def getPDE(self):
-        """
-        Return the underlying PDE.
-
-        :rtype: `LinearPDE`
-        """
-        return self.__pde
-
-    def _getDefect(self, result):
-        """
-        Returns the defect value.
-
-        :param result: a result vector
-        :type result: `Vector`
-        :rtype: ``float``
-        """
-        A=0.
-        for s in range(len(self.__weight)):
-            A += integrate( inner(self.__weight[s], self.__data[s]-result)**2 )
-        return  A/2
-
-    def getDefectGradient(self, result):
-        Y=0.
-        for s in range(len(self.__weight)):
-            Y = inner(self.__weight[s], self.__data[s]-result) * self.__weight[s] + Y
-        return Y
-
-    def getSurvey(self, index=None):
-        """
-        Returns the pair (data_index, weight_index), where data_i is the data
-        of survey i, weight_i is the weighting factor for survey i.
-        If index is None, all surveys will be returned in a pair of lists.
-        """
-        if index is None:
-            return self.__data, self.__weight
-        if index>=len(self.__data):
-            raise IndexError("Forward model only has %d surveys"%len(self.__data))
-        return self.__data[index], self.__weight[index]
-
-
-
-class GravityModel(ForwardModelWithPotential):
-    """
-    Forward Model for gravity inversion as described in the inversion
-    cookbook.
-    """
-    def __init__(self, domain, w, g,  gravity_constant=U.Gravitational_Constant,
-                  coordinates=None, fixPotentialAtBottom=False, tol=1e-8):
-        """
-        Creates a new gravity model on the given domain with one or more
-        surveys (w, g).
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param w: data weighting factors
-        :type w: ``Vector`` or list of ``Vector``
-        :param g: gravity anomaly data
-        :type g: ``Vector`` or list of ``Vector``
-        :param coordinates: defines coordinate system to be used
-        :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        :param fixPotentialAtBottom: if true potential is fixed to zero at the bottom of the domain
-                                     in addition to the top.
-        :type fixPotentialAtBottom: ``bool``
-
-
-        :note: It is advisable to call rescaleWeights() to rescale weights before start inversion.
-        """
-        super(GravityModel, self).__init__(domain, w, g, coordinates, fixPotentialAtBottom, tol)
-
-        trafo = self.getCoordinateTransformation()
-        if not trafo.isCartesian():
-            self.__G = 4*PI*gravity_constant * trafo.getVolumeFactor()
-                    #* trafo.getReferenceSystem().getHeightUnit()**(-3)
-
-            fw = trafo.getScalingFactors()**2 * trafo.getVolumeFactor()
-            A=self.getPDE().createCoefficient("A")
-            for i in range(self.getDomain().getDim()): A[i,i]=fw[i]
-            self.getPDE().setValue(A=A)
-        else: # cartesian
-            self.__G = 4*PI*gravity_constant
-            self.getPDE().setValue(A=kronecker(self.getDomain()))
-
-    def rescaleWeights(self, scale=1., rho_scale=1.):
-        """
-        rescales the weights such that
-
-        *sum_s integrate( ( w_i[s] *g_i[s]) (w_j[s]*1/L_j) * L**2 * 4*pi*G*rho_scale )=scale*
-
-        :param scale: scale of data weighting factors
-        :type scale: positive ``float``
-        :param rho_scale: scale of density.
-        :type rho_scale: ``Scalar``
-        """
-        self._rescaleWeights(scale, self.__G*rho_scale)
-
-    def getArguments(self, rho):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param rho: a suggestion for the density distribution
-        :type rho: ``Scalar``
-        :return: gravity potential and corresponding gravity field.
-        :rtype: ``Scalar``, ``Vector``
-        """
-        phi = self.getPotential(rho)
-        gravity_force = -grad(phi)
-        return phi, gravity_force
-
-    def getPotential(self, rho):
-        """
-        Calculates the gravity potential for a given density distribution.
-
-        :param rho: a suggestion for the density distribution
-        :type rho: ``Scalar``
-        :return: gravity potential
-        :rtype: ``Scalar``
-        """
-        pde=self.getPDE()
-
-        pde.resetRightHandSideCoefficients()
-        pde.setValue(Y=-self.__G*rho)
-        phi=pde.getSolution()
-
-        return phi
-
-    def getDefect(self, rho, phi, gravity_force):
-        """
-        Returns the value of the defect
-
-        :param rho: density distribution
-        :type rho: ``Scalar``
-        :param phi: corresponding potential
-        :type phi: ``Scalar``
-        :param gravity_force: gravity force
-        :type gravity_force: ``Vector``
-        :rtype: ``float``
-        """
-        return self._getDefect(gravity_force)
-
-    def getGradient(self, rho, phi, gravity_force):
-        """
-        Returns the gradient of the defect with respect to density.
-
-        :param rho: density distribution
-        :type rho: ``Scalar``
-        :param phi: corresponding potential
-        :type phi: ``Scalar``
-        :param gravity_force: gravity force
-        :type gravity_force: ``Vector``
-        :rtype: ``Scalar``
-        """
-        pde=self.getPDE()
-        pde.resetRightHandSideCoefficients()
-        pde.setValue(X=self.getDefectGradient(gravity_force))
-        ZT=pde.getSolution()
-        return ZT*(-self.__G)
-
-class IsostaticPressure(object):
-    """
-    class to calculate isostatic pressure field correction due to gravity forces 
-    """
-    def __init__(self, domain, p0=0.,
-                        level0=0, 
-                        gravity0=-9.81 * U.m*U.sec**(-3),
-                        background_density= 2670* U.kg*U.m**(-3),
-                        gravity_constant=U.Gravitational_Constant, 
-                        coordinates=None, 
-                        tol=1e-8):
-        """
-        
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param p0: pressure at level0
-        :type p0: scalar `Data` or ``float``
-        :param background_density: defines background_density in kg/m^3
-        :type background_density: ``float``
-        :param coordinates: defines coordinate system to be used
-        :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        :param level0: pressure for z>=`level0` is set to zero.
-        :type level0: ``float``
-        :param gravity0: vertical background gravity at `level0`
-        :type gravity0: ``float``        
-        """
-        DIM=domain.getDim()
-        self.__domain = domain
-        self.__trafo=makeTranformation(domain, coordinates)
-        
-        self.__pde=LinearSinglePDE(domain)
-        self.__pde.getSolverOptions().setTolerance(tol)
-        self.__pde.setSymmetryOn()
-
-        z = domain.getX()[DIM-1]
-        self.__pde.setValue(q=whereNonNegative(z-level0), r=p0)
-
-        fw = self.__trafo.getScalingFactors()**2 * self.__trafo.getVolumeFactor()
-        A=self.__pde.createCoefficient("A")
-        for i in range(DIM): A[i,i]=fw[i]
-        self.__pde.setValue(A=A)
-        z = Function(domain).getX()[DIM-1]
-        self.__g_b= 4*PI*gravity_constant/self.__trafo.getScalingFactors()[DIM-1]*background_density*(level0-z) + gravity0
-        self.__rho_b=background_density
-        
-    def getPressure(self, g = None, rho=None):
-        """
-        return the pressure for gravity force anomaly `g` and 
-        density anomaly `density`
-        
-        :param g: gravity anomaly data
-        :type g: ``Vector`` 
-        :param rho: gravity anomaly data
-        :type rho: ``Scalar`` 
-        :return: pressure distribution
-        :rtype: ``Scalar`
-        """
-        if not g: g=Vector(0., Function(self.__domain))
-        if not rho: rho=Scalar(0., Function(self.__domain))
-        
-        g2=(rho * self.__g_b)*[0,0,1] + self.__rho_b*g + rho*g 
-        # Tests need to be updated before the following is uncommented:
-        #g2=((rho+self.__rho_b) * self.__g_b)*[0,0,1] + self.__rho_b*g + rho*g 
-        d=self.__trafo.getScalingFactors()
-        V= self.__trafo.getVolumeFactor()
-        self.__pde.setValue(X = -g2*d*V)
-        #self.__pde.setValue(X = g2*d*V)
-        return self.__pde.getSolution()
-
-    
-class MagneticModel(ForwardModelWithPotential):
-    """
-    Forward Model for magnetic inversion as described in the inversion
-    cookbook.
-    """
-    def __init__(self, domain, w, B, background_magnetic_flux_density, coordinates=None, fixPotentialAtBottom=False, tol=1e-8):
-        """
-        Creates a new magnetic model on the given domain with one or more
-        surveys (w, B).
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param w: data weighting factors
-        :type w: ``Vector`` or list of ``Vector``
-        :param B: magnetic field data
-        :type B: ``Vector`` or list of ``Vector``
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        :param background_magnetic_flux_density: background magnetic flux
-               density (in Tesla) with components (B_east, B_north, B_vertical)
-        :type background_magnetic_flux_density: ``Vector`` or list of `float`
-        :param coordinates: defines coordinate system to be used
-        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param fixPotentialAtBottom: if true potential is fixed to zero at the
-                                     bottom of the domain in addition to the top
-        :type fixPotentialAtBottom: ``bool``
-        """
-        super(MagneticModel, self).__init__(domain, w, B, coordinates, fixPotentialAtBottom, tol)
-        background_magnetic_flux_density =interpolate(background_magnetic_flux_density, B[0].getFunctionSpace())
-        if not self.getCoordinateTransformation().isCartesian():
-            #self.__F = self.getCoordinateTransformation().getVolumeFactor()
-            self.__B_r=background_magnetic_flux_density*self.getCoordinateTransformation().getScalingFactors()*self.getCoordinateTransformation().getVolumeFactor()
-            self.__B_b=background_magnetic_flux_density/self.getCoordinateTransformation().getScalingFactors()
-
-            A=self.getPDE().createCoefficient("A")
-            fw=self.getCoordinateTransformation().getScalingFactors()**2*self.getCoordinateTransformation().getVolumeFactor()
-            for i in range(self.getDomain().getDim()): A[i,i]=fw[i]
-            self.getPDE().setValue(A=A)
-        else: # cartesian
-            self.getPDE().setValue(A=kronecker(self.getDomain()))
-            self.__B_r=background_magnetic_flux_density
-            self.__B_b=background_magnetic_flux_density
-
-    def rescaleWeights(self, scale=1., k_scale=1.):
-        """
-        rescales the weights such that
-
-        *sum_s integrate( ( w_i[s] *B_i[s]) (w_j[s]*1/L_j) * L**2 * (background_magnetic_flux_density_j[s]*1/L_j) * k_scale )=scale*
-
-        :param scale: scale of data weighting factors
-        :type scale: positive ``float``
-        :param k_scale: scale of susceptibility.
-        :type k_scale: ``Scalar``
-        """
-        self._rescaleWeights(scale, inner(self.__B_r,1/self.edge_lengths ) * k_scale)
-
-    def getArguments(self, k):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :return: scalar magnetic potential and corresponding magnetic field
-        :rtype: ``Scalar``, ``Vector``
-        """
-        phi = self.getPotential(k)
-        magnetic_flux_density = k * self.__B_b -grad(phi)
-        return phi, magnetic_flux_density
-
-    def getPotential(self, k):
-        """
-        Calculates the magnetic potential for a given susceptibility.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :return: magnetic potential
-        :rtype: ``Scalar``
-        """
-        pde=self.getPDE()
-
-        pde.resetRightHandSideCoefficients()
-        pde.setValue(X = k* self.__B_r)
-        phi=pde.getSolution()
-
-        return phi
-
-    def getDefect(self, k, phi, magnetic_flux_density):
-        """
-        Returns the value of the defect.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :param phi: corresponding potential
-        :type phi: ``Scalar``
-        :param magnetic_flux_density: magnetic field
-        :type magnetic_flux_density: ``Vector``
-        :rtype: ``float``
-        """
-        return self._getDefect(magnetic_flux_density)
-
-    def getGradient(self, k, phi, magnetic_flux_density):
-        """
-        Returns the gradient of the defect with respect to susceptibility.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :param phi: corresponding potential
-        :type phi: ``Scalar``
-        :param magnetic_flux_density: magnetic field
-        :type magnetic_flux_density: ``Vector``
-        :rtype: ``Scalar``
-        """
-        Y=self.getDefectGradient(magnetic_flux_density)
-        pde=self.getPDE()
-        pde.resetRightHandSideCoefficients()
-        pde.setValue(X=Y)
-        YT=pde.getSolution()
-        return inner(grad(YT),self.__B_r) -inner(Y,self.__B_b)
-
-class SelfDemagnetizationModel(ForwardModelWithPotential):
-    """
-    Forward Model for magnetic inversion with self-demagnetization as
-    described in the inversion cookbook.
-    """
-    def __init__(self, domain, w, B, background_magnetic_flux_density, coordinates=None, fixPotentialAtBottom=False, tol=1e-8):
-        """
-        Creates a new magnetic model on the given domain with one or more
-        surveys (w, B).
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param w: data weighting factors
-        :type w: ``Vector`` or list of ``Vector``
-        :param B: magnetic field data
-        :type B: ``Vector`` or list of ``Vector``
-        :param background_magnetic_flux_density: background magnetic flux
-               density (in Tesla) with components (B_east, B_north, B_vertical)
-        :type background_magnetic_flux_density: ``Vector`` or list of `float`
-        :param coordinates: defines coordinate system to be used
-        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param fixPotentialAtBottom: if true potential is fixed to zero at the
-                                     bottom of the domain in addition to the top
-        :type fixPotentialAtBottom: ``bool``
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        """
-        super(SelfDemagnetizationModel, self).__init__(domain, w, B, coordinates, fixPotentialAtBottom, tol)
-        #=========================================================
-        background_magnetic_flux_density = interpolate(background_magnetic_flux_density, B[0].getFunctionSpace())
-        if not self.getCoordinateTransformation().isCartesian():
-            #self.__F = self.getCoordinateTransformation().getVolumeFactor()
-            self.__B_r=background_magnetic_flux_density*self.getCoordinateTransformation().getScalingFactors()*self.getCoordinateTransformation().getVolumeFactor()
-            self.__B_b=background_magnetic_flux_density/self.getCoordinateTransformation().getScalingFactors()
-
-            self.__fw=self.getCoordinateTransformation().getScalingFactors()**2*self.getCoordinateTransformation().getVolumeFactor()
-        else: # cartesian
-            self.__fw=1
-            self.__B_r=background_magnetic_flux_density
-            self.__B_b=background_magnetic_flux_density
-
-        # keep track of k used to build PDE:
-        self.__last_k=None
-        # this is just the initial set_up
-        A=self.getPDE().createCoefficient("A")
-        for i in range(self.getDomain().getDim()): A[i,i]=1.
-        self.getPDE().setValue(A=A)
-
-    def rescaleWeights(self, scale=1., k_scale=1.):
-        """
-        rescales the weights such that
-
-        *sum_s integrate( ( w_i[s] *B_i[s]) (w_j[s]*1/L_j) * L**2 * (background_magnetic_flux_density_j[s]*1/L_j) * k_scale )=scale*
-
-        :param scale: scale of data weighting factors
-        :type scale: positive ``float``
-        :param k_scale: scale of susceptibility.
-        :type k_scale: ``Scalar``
-        """
-        self._rescaleWeights(scale, inner(self.__B_r,1/self.edge_lengths ) * k_scale)
-
-    def getArguments(self, k):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :return: scalar magnetic potential and corresponding magnetic field
-        :rtype: ``Scalar``, ``Vector``
-        """
-        phi = self.getPotential(k)
-        grad_phi=grad(phi)
-        magnetic_flux_density = k * self.__B_b -(1+k)*grad_phi
-        return phi, grad_phi, magnetic_flux_density
-
-    def __updateA(self, k):
-        """
-        updates PDE coefficient if PDE is used with new k
-        """
-        pde=self.getPDE()
-        if self.__last_k is not k:
-           A=pde.getCoefficient('A')
-           if self.getCoordinateTransformation().isCartesian():
-               for i in range(self.getDomain().getDim()): A[i,i]=(1+k)
-           else:
-               for i in range(self.getDomain().getDim()): A[i,i]=(1+k)*self.__fw[i]
-           self.__last_k = k
-           pde.setValue(A=A)
-
-    def getPotential(self, k):
-        """
-        Calculates the magnetic potential for a given susceptibility.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :return: magnetic potential
-        :rtype: ``Scalar``
-        """
-        self.__updateA(k)
-        pde=self.getPDE()
-        pde.resetRightHandSideCoefficients()
-        pde.setValue(X = k* self.__B_r)
-        phi=pde.getSolution()
-        return phi
-
-    def getDefect(self, k, phi, grad_phi, magnetic_flux_density):
-        """
-        Returns the value of the defect.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :param phi: corresponding potential
-        :type phi: ``Scalar``
-        :param magnetic_flux_density: magnetic field
-        :type magnetic_flux_density: ``Vector``
-        :rtype: ``float``
-        """
-        return self._getDefect(magnetic_flux_density)
-
-    def getGradient(self, k, phi, grad_phi, magnetic_flux_density):
-        """
-        Returns the gradient of the defect with respect to susceptibility.
-
-        :param k: susceptibility
-        :type k: ``Scalar``
-        :param phi: corresponding potential
-        :type phi: ``Scalar``
-        :param magnetic_flux_density: magnetic field
-        :type magnetic_flux_density: ``Vector``
-        :rtype: ``Scalar``
-        """
-        self.__updateA(k)
-        Y=self.getDefectGradient(magnetic_flux_density)
-        pde=self.getPDE()
-        pde.resetRightHandSideCoefficients()
-        pde.setValue(X=(1+k)*Y)
-        grad_YT=grad(pde.getSolution())
-
-        if self.getCoordinateTransformation().isCartesian(): # then b_r=B_b
-            return inner(grad_YT-Y, self.__B_r-grad_phi)
-        else:
-            return inner(grad_YT,self.__B_r-grad_phi)+inner(Y,grad_phi-self.__B_b)
-
-class AcousticWaveForm(ForwardModel):
-    """
-    Forward Model for acoustic waveform inversion in the frequency domain.
-    It defines a cost function:
-
-        defect = 1/2 integrate( ( w * ( a * u - data ) ) ** 2 )
-
-    where w are weighting factors, data are the measured data (as a 2-comp
-    vector of real and imaginary part) for real frequency omega, and u is
-    the corresponding result produced by the forward model.
-    u (as a 2-comp vector) is the solution of the complex Helmholtz equation
-    for frequency omega, source F and complex, inverse, squared p-velocity
-    sigma:
-
-        * -u_{ii} - omega**2 * sigma * u = F
-
-    It is assumed that the exact scale of source F is unknown and the scaling
-    factor a of F is calculated by minimizing the defect.
-    """
-    def __init__(self, domain, omega, w, data, F, coordinates=None, fixAtBottom=False, tol=1e-8, saveMemory=True, scaleF=True):
-        """
-        initializes a new forward model with acoustic wave form inversion.
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param w: weighting factors
-        :type w: ``Scalar``
-        :param data: real and imaginary part of data
-        :type data: ``Data`` of shape (2,)
-        :param F: real and imaginary part of source given at Dirac points,
-                  on surface or at volume.
-        :type F: ``Data`` of shape (2,)
-        :param coordinates: defines coordinate system to be used (not supported yet)
-        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        :param saveMemory: if true stiffness matrix is deleted after solution
-                           of PDE to minimize memory requests. This will
-                           require more compute time as the matrix needs to be
-                           reallocated.
-        :type saveMemory: ``bool``
-        :param scaleF: if true source F is scaled to minimize defect.
-        :type scaleF: ``bool``
-        :param fixAtBottom: if true pressure is fixed to zero at the bottom of
-                            the domain
-        :type fixAtBottom: ``bool``
-        """
-        super(AcousticWaveForm, self).__init__()
-        self.__domain = domain
-        self.__omega=omega
-        self.scaleF=scaleF
-        self.__trafo=makeTranformation(domain, coordinates)
-        if not self.getCoordinateTransformation().isCartesian():
-            raise ValueError("Non-Cartesian Coordinates are not supported yet.")
-        if not isinstance(data, Data):
-                raise ValueError("data must be an escript.Data object.")
-        if not data.getFunctionSpace() == FunctionOnBoundary(domain):
-                raise ValueError("data must be defined on boundary")
-        if not data.getShape() == (2,):
-                raise ValueError("data must have shape 2 (real and imaginary part).")
-        if w is None:
-            w = 1.
-        if not isinstance(w, Data):
-            w=Data(w, FunctionOnBoundary(domain))
-        else:
-            if not w.getFunctionSpace() == FunctionOnBoundary(domain):
-                raise ValueError("Weights must be defined on boundary.")
-            if not w.getShape() == ():
-                raise ValueError("Weights must be scalar.")
-        self.__weight = w
-        self.__data = data
-        if scaleF:
-            A = integrate(self.__weight*length(self.__data)**2)
-            if A>0:
-                self.__data*=1./sqrt(A)
-
-        self.__BX = boundingBox(domain)
-        self.edge_lengths=np.asarray(boundingBoxEdgeLengths(domain))
-
-        self.__F=Data()
-        self.__f=Data()
-        self.__f_dirac=Data()
-
-        if not isinstance(F, Data):
-            F=interpolate(F,  DiracDeltaFunctions(domain))
-        if not F.getShape() == (2,):
-            raise ValueError("Source must have shape (2,) (real and imaginary part).")
-
-        if F.getFunctionSpace() == DiracDeltaFunctions(domain):
-            self.__f_dirac=F
-        elif F.getFunctionSpace() == FunctionOnBoundary(domain):
-            self.__f=F
-        else:
-            self.__F=F
-        self.__tol=tol
-        self.__fixAtBottom=fixAtBottom
-        self.__pde=None
-        if not saveMemory:
-            self.__pde=self.setUpPDE()
-
-    def getSurvey(self, index=None):
-        """
-        Returns the pair (data, weight)
-
-        If argument index is ignored.
-        """
-        return self.__data, self.__weight
-
-    def rescaleWeights(self, scale=1., sigma_scale=1.):
-        """
-        rescales the weights such that
-
-        *integrate( ( w omega**2 * sigma_scale * data * ((1/L_j)**2)**-1) +1 )/(data*omega**2 * ((1/L_j)**2)**-1) * sigma_scale )=scale*
-
-        :param scale: scale of data weighting factors
-        :type scale: positive ``float``
-        :param sigma_scale: scale of 1/vp**2 velocity.
-        :type sigma_scale: ``Scalar``
-        """
-        raise Warning("rescaleWeights is not tested yet.")
-        if not scale > 0:
-             raise ValueError("Value for scale must be positive.")
-        if not sigma_scale*omega**2*d > 0:
-             raise ValueError("Rescaling of weights failed due to zero denominator.")
-        # copy back original weights before rescaling
-        #self.__weight=[1.*ow for ow in self.__origweight]
-        L2=1/length(1/self.edge_length)**2
-        d=Lsup(length(data))
-        A=integrate(self.__weight*(sigma_scale*omega**2*d+1)/(sigma_scale*omega**2*d) )
-        if A > 0:
-            self.__weight*=1./A
-            if self.scaleF: self.__data*=sqrt(A)
-        else:
-            raise ValueError("Rescaling of weights failed.")
-
-    def getDomain(self):
-        """
-        Returns the domain of the forward model.
-
-        :rtype: `Domain`
-        """
-        return self.__domain
-
-    def getCoordinateTransformation(self):
-        """
-        returns the coordinate transformation being used
-
-        :rtype: ``CoordinateTransformation``
-        """
-        return self.__trafo
-
-    def setUpPDE(self):
-        """
-        Creates and returns the underlying PDE.
-
-        :rtype: `LinearPDE`
-        """
-        from esys.escript import getEscriptParamInt
-        if self.__pde is None:
-            pde=LinearPDE(self.__domain, numEquations=2)
-            D=pde.createCoefficient('D')
-            A=pde.createCoefficient('A')
-            A[0,:,0,:]=kronecker(self.__domain.getDim())
-            A[1,:,1,:]=kronecker(self.__domain.getDim())
-            pde.setValue(A=A, D=D)
-            if self.__fixAtBottom:
-                DIM=self.__domain.getDim()
-                z = self.__domain.getX()[DIM-1]
-                pde.setValue(q=whereZero(z-self.__BX[DIM-1][0])*[1,1])
-
-            if getEscriptParamInt("PASO_DIRECT")==0:
-                raise ValueError("Either this build of escript or the current MPI configuration does not support direct solvers.")
-            pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT)
-            pde.getSolverOptions().setTolerance(self.__tol)
-            pde.setSymmetryOff()
-        else:
-            pde=self.__pde
-            pde.resetRightHandSideCoefficients()
-        return pde
-
-    def getSourceScaling(self, u):
-        """
-        returns the scaling factor s required to rescale source F to minimize defect |s * u- data|^2
-        :param u: value of pressure solution (real and imaginary part)
-        :type u: ``Data`` of shape (2,)
-        :rtype: `complex`
-        """
-        uTu=integrate(self.__weight * length(u)**2)
-        uTar=integrate(self.__weight * ( u[0]*self.__data[0]+u[1]*self.__data[1]) )
-        uTai=integrate(self.__weight * ( u[0]*self.__data[1]-u[1]*self.__data[0]) )
-        if uTu > 0:
-            return complex(uTar/uTu, uTai/uTu)
-        else:
-            return complex(1.,0)
-
-    def getArguments(self, sigma):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param sigma: a suggestion for complex 1/V**2
-        :type sigma: ``Data`` of shape (2,)
-        :return: solution,  uTar, uTai, uTu
-        :rtype: ``Data`` of shape (2,), 3 x `float`
-        """
-        pde=self.setUpPDE()
-        D=pde.getCoefficient('D')
-        D[0,0]=-self.__omega**2 * sigma[0]
-        D[0,1]= self.__omega**2 * sigma[1]
-        D[1,0]=-self.__omega**2 * sigma[1]
-        D[1,1]=-self.__omega**2 * sigma[0]
-        pde.setValue(D=D, Y=self.__F, y=self.__f, y_dirac=self.__f_dirac)
-        u=pde.getSolution()
-
-        uTar=integrate(self.__weight * ( u[0]*self.__data[0]+u[1]*self.__data[1]) )
-        uTai=integrate(self.__weight * ( u[0]*self.__data[1]-u[1]*self.__data[0]) )
-        uTu = integrate( self.__weight * length(u)**2 )
-        return u, uTar, uTai, uTu
-
-    def getDefect(self, sigma, u, uTar, uTai, uTu):
-        """
-        Returns the defect value.
-
-        :param sigma: a suggestion for complex 1/V**2
-        :type sigma: ``Data`` of shape (2,)
-        :param u: a u vector
-        :type u: ``Data`` of shape (2,)
-        :param uTar: equals `integrate( w  * (data[0]*u[0]+data[1]*u[1]))`
-        :type uTar: `float`
-        :param uTai: equals `integrate( w  * (data[1]*u[0]-data[0]*u[1]))`
-        :type uTa: `float`
-        :param uTu: equals `integrate( w  * (u,u))`
-        :type uTu: `float`
-
-        :rtype: ``float``
-        """
-        # assuming integrate(w * length(data)**2) =1
-        if self.scaleF and abs(uTu) >0:
-           A = 1.-(uTar**2 + uTai**2)/uTu
-        else:
-           A = integrate(self.__weight*length(self.__data)**2)- 2 * uTar + uTu
-        return  A/2
-
-    def getGradient(self, sigma, u, uTar, uTai, uTu):
-        """
-        Returns the gradient of the defect with respect to density.
-
-        :param sigma: a suggestion for complex 1/V**2
-        :type sigma: ``Data`` of shape (2,)
-        :param u: a u vector
-        :type u: ``Data`` of shape (2,)
-        :param uTar: equals `integrate( w  * (data[0]*u[0]+data[1]*u[1]))`
-        :type uTar: `float`
-        :param uTai: equals `integrate( w  * (data[1]*u[0]-data[0]*u[1]))`
-        :type uTa: `float`
-        :param uTu: equals `integrate( w  * (u,u))`
-        :type uTu: `float`
-        """
-        pde=self.setUpPDE()
-
-        if self.scaleF and abs(uTu) >0:
-            Z=((uTar**2+uTai**2)/uTu**2) *interpolate(u, self.__data.getFunctionSpace())
-            Z[0]+= (-uTar/uTu) * self.__data[0]+ (-uTai/uTu) * self.__data[1]
-            Z[1]+= (-uTar/uTu) * self.__data[1]+   uTai/uTu  * self.__data[0]
-
-        else:
-            Z= u - self.__data
-        if Z.getFunctionSpace() == DiracDeltaFunctions(self.getDomain()):
-            pde.setValue(y_dirac=self.__weight * Z)
-        else:
-            pde.setValue(y=self.__weight * Z)
-        D=pde.getCoefficient('D')
-        D[0,0]=-self.__omega**2 * sigma[0]
-        D[0,1]=-self.__omega**2 * sigma[1]
-        D[1,0]= self.__omega**2 * sigma[1]
-        D[1,1]=-self.__omega**2 * sigma[0]
-        pde.setValue(D=D)
-        ZTo2=pde.getSolution()*self.__omega**2
-        return inner(ZTo2,u)*[1,0]+(ZTo2[1]*u[0]-ZTo2[0]*u[1])*[0,1]
-
-class DcRes(ForwardModel):
-    """
-    Forward Model for dc resistivity, with a given source pair.
-    The cost function is defined as:
-
-        * defect = 1/2 (sum_s sum_pq w_pqs * ((phi_sp-phi_sq)-v_pqs)**2 *
-
-    where p and q indate the 
-
-    """
-    def __init__(self, domain, locator, delphi_in, sampleTags, phiPrimary, sigmaPrimary, w=1., coordinates=None, tol=1e-8,saveMemory=True,b=None):
-        
-        """
-        setup new ForwardModel
-        :param domain: the domain of the model
-        :type: escript domain
-        :param locator: contains locator to the measurement pairs
-        :type: `list` of ``Locator``
-        :param: delphi_in: this is v_pq, the potential difference for the current source  and a set of measurement pairs. a list of measured potential differences is expected. Note this should be the secondary potential only. 
-        :type delphi_in: tuple
-        :param sampleTags:  tags of measurement points from which potential differences will be calculated.
-        :type sampleTags: list of tuples
-        :param phiPrimary: primary potential.
-        :type phiPrimary: `Scalar`
-        """
-        super(DcRes, self).__init__()
-
-        self.__domain=domain
-        self.__tol = tol
-        self.__locator=locator
-        self.__trafo=makeTranformation(domain, coordinates) 
-        self.__delphi_in=delphi_in
-        self.__sampleTags = sampleTags
-        self.__sigmaPrimary = sigmaPrimary
-
-        if not isinstance(sampleTags, list):
-            raise ValueError("sampleTags must be a list.")    
-        if not len(sampleTags) == len(delphi_in):
-            raise ValueError("sampleTags and delphi_in must have the same length.")  
-        if not len(sampleTags)>0:
-            raise ValueError("sampleTags list is empty.")    
-        if not isinstance(sampleTags[0], tuple):
-            raise ValueError("sampleTags must be a list of tuple.")    
-
-        if isinstance(w, float) or isinstance(w, int):
-               w =[ float(w) for z in delphi_in]
-               self.__w=w
-        if not len(w) == len(delphi_in):
-               raise ValueError("Number of confidence factors and number of potential input values don't match.")
-
-        self.__phiPrimary=phiPrimary
-        if not self.getCoordinateTransformation().isCartesian():
-            raise ValueError("Non-Cartesian Coordinates are not supported yet.")
-        if not isinstance(locator, Locator):
-            raise ValueError("locator must be an escript locator object")    
-        
-        
-        self.__pde=None        
-        if not saveMemory:
-            self.__pde=self.setUpPDE()
-
-    def getDomain(self):
-        """
-        Returns the domain of the forward model.
-
-        :rtype: `Domain`
-        """
-        return self.__domain
-
-    def getCoordinateTransformation(self):
-        """
-        returns the coordinate transformation being used
-
-        :rtype: ``CoordinateTransformation``
-        """
-        return self.__trafo
-
-    def getPrimaryPotential(self):
-        """
-        returns the primary potential
-        :rtype: `Data`
-        """
-        return self.__phiPrimary 
-
-    def setUpPDE(self):
-        """
-        Return the underlying PDE.
-
-        :rtype: `LinearPDE`
-        """
-        if self.__pde is None:
-            dom=self.__domain
-            x = dom.getX()
-            DIM=dom.getDim()
-            q=whereZero(x[DIM-1]-inf(x[DIM-1]))
-            for i in xrange(DIM-1):
-                xi=x[i]
-                q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
-            
-            pde=LinearPDE(dom, numEquations=1)
-            pde.getSolverOptions().setTolerance(self.__tol)
-            pde.setSymmetryOn()
-            A=pde.createCoefficient('A')
-            X=pde.createCoefficient('X')
-            pde.setValue(A=A,X=X,q=q)
-
-            # else:
-                # pde=LinearPDE(self.__domain, numEquations=1)   
-                # A=pde.createCoefficient('A')
-                # z = dom.getX()[DIM-1]
-                # q=whereZero(z-inf(z))
-                # r=0
-                # pde.setValue(A=APrimary,y_dirac=y_dirac,d=alpha)
-
-        else:
-            pde=self.__pde
-            pde.resetRightHandSideCoefficients()
-        return pde
-
-    def getArguments(self, sigma):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param sigma: conductivity
-        :type sigma: ``Data`` of shape (1,)
-        :return: phi
-        :rtype: ``Data`` of shape (1,)
-        """
-        # print "sigmaPrimary",self.__sigmaPrimary
-        # print "sigma=",sigma
-        dom=self.__domain
-        pde=self.setUpPDE()
-        X=(self.__sigmaPrimary - sigma) * grad(self.__phiPrimary)
-        # print "+++++++++++++++++++"
-        # print "sigma=",sigma
-        # print "A=",A
-        # print "X=",X
-        # print "+++++++++++++++++++"
-        pde.setValue(A=sigma * kronecker(dom),X=X)
-        phi=pde.getSolution()        
-        # print "got U Sol"
-        #u.expand()
-        # print "u=",u,"grad(u)=",grad(u)
-        loc=self.__locator
-        loc_phi=loc.getValue(phi)
-        # print "read %s at %s"%(str(val),str(loc.getX()))
-        return phi, loc_phi
-
-   
-    def getDefect(self, sigma, phi, loc_phi):
-        """
-        Returns the defect value.
-
-        :param sigma: a suggestion for conductivity
-        :type sigma: ``Data`` of shape (1,)
-        :param phi: potential field
-        :type phi: ``Data`` of shape (1,)
-        
-        :rtype: ``float``
-        """
-        # print ("getting Defect")
-        # print "sigma=",sigma
-        # print "placeholder=",placeholder
-        val=loc_phi
-        if not isinstance(val,list):
-            tmp=val
-            val=[tmp]
-        # print "val=",val
-        length=len(val)
-        # print self.__sampleTags[0] 
-        if((self.__sampleTags[0][1]!="-" and (length%2) != 0) or (self.__sampleTags[0][1]!="-" and length/2 != len(self.__delphi_in))):
-            raise ValueError("length of locator is wrong")
-
-        delphi_calc=[]
-        if self.__sampleTags[0][1]!="-":
-            for i in range(0,length,2):
-                delphi_calc.append(val[i+1]-val[i])
-        else:
-            for i in range(length):
-                delphi_calc.append(val[i])
-        A=0
-        if (self.__sampleTags[0][1]!="-"):
-            for i in range(length//2):
-                A+=(self.__w[i]*(delphi_calc[i]-self.__delphi_in[i])**2)        
-                # print "delphi_calc[i]=",delphi_calc[i],"self.__delphi_in[i]",self.__delphi_in[i] 
-        else:
-            for i in range(length):
-                A+=(self.__w[i]*(delphi_calc[i]-self.__delphi_in[i])**2)        
-                # A+=(self.__w[i]*(self.__delphi_in[i]-delphi_calc[i])**2)        
-                # print "delphi_calc[i]=",delphi_calc[i],"self.__delphi_in[i]",self.__delphi_in[i] 
-        return  A/2
-
-    def getGradient(self, sigma, phi, loc_phi):
-        """
-        Returns the gradient of the defect with respect to density.
-
-        :param sigma: a suggestison for conductivity
-        :type sigma: ``Data`` of shape (1,)
-        :param phi: potential field
-        :type phi: ``Data`` of shape (1,)
-        """
-        # print ("getting gradient")
-        # print "sigma=",sigma
-        val=loc_phi
-        if not isinstance(val,list):
-            tmp=val
-            val=[tmp]
-        sampleTags=self.__sampleTags
-
-        jointSamples={}
-        # print(sampleTags)
-        for i in range(0,2*len(sampleTags),2): #2*len because sample tags is a list of tuples
-            half = i//2
-            # print(i)
-            if sampleTags[half][1]!="-":
-                tmp=(val[i+1]-val[i]-self.__delphi_in[half])*self.__w[i]
-            else:
-                tmp=(val[i]-self.__delphi_in[i//2]) *self.__w[i]
-                # tmp=self.__delphi_in[i/2]-val[i]
-            # print ("in gradient","i=", i,"val[i]=",-val[i],"self.__delphi_in[i/2]=",self.__delphi_in[i/2])
-            # print ("tmp=",tmp)
-            sample = sampleTags[half]
-            if sample[1]!="-":
-                if sample[0] in jointSamples.keys():
-                    jointSamples[sample[0]].append((sample[1], -tmp))
-                else:
-                    jointSamples[sampleTags[half][0]]=[(sample[1],-tmp)]
-                if sample[1] in jointSamples.keys():
-                    jointSamples[sample[1]].append((sample[0], tmp))
-                else:
-                    jointSamples[sample[1]]=[(sample[0], tmp)]
-            else:
-                if sample[0] in jointSamples.keys():
-                    jointSamples[sample[0]].append((sample[1], tmp))
-                else:
-                    jointSamples[sampleTags[half][0]]=[(sample[1],tmp)]
-
-#        print ("jointSamples=",jointSamples)
-        pde =self.setUpPDE()
-        dom=self.__domain
-        # conPrimary=self.__sigmaPrimary
-        # APrimary = conPrimary * kronecker(dom)
-
-        y_dirac = Scalar(0,DiracDeltaFunctions(dom))
-        for i in jointSamples:
-            total=0
-            for j in jointSamples[i]:
-                total+=j[1]
-#            print("setting y_dirac ", i, " to ", total)
-            y_dirac.setTaggedValue(i,total)
-
-        pde.setValue(A=sigma*kronecker(dom), y_dirac=y_dirac)
-        u=pde.getSolution()
-        retVal=-inner(grad(u),grad(phi+self.__phiPrimary))
-        return retVal
-
-
-class MT2DModelTEMode(ForwardModel):
-    """
-    Forward Model for two dimensional MT model in the TE mode for a given
-    frequency omega.
-    It defines a cost function:
-
-      *  defect = 1/2 integrate( sum_s w^s * ( E_x - Z_XY^s * H_y ) ) ** 2  *
-
-    where E_x is the horizontal electric field perpendicular to the YZ-domain,
-    horizontal magnetic field H_y=1/(i*omega*mu) * E_{x,z} with complex unit
-    i and permeability mu. The weighting factor w^s is set to
-
-        * w^s(X) = w_0^s/(2pi*eta**2) * exp(-length(X-X^s)**2/(2*eta**2))  *
-
-    where X^s is the location of impedance measurement Z_XY^s, w_0 is the level
-    of confidence (eg. 1/measurement error) and eta is level of spatial
-    confidence.
-
-    E_x is given as solution of the PDE
-
-        * -E_{x,ii} - i omega * mu * sigma * E_x = 0
-
-    where E_x is set to E_0 on the top of the domain. Homogeneous Neuman
-    conditions are assumed elsewhere.
-    """
-    def __init__(self, domain, omega, x, Z_XY, eta, w0=1., mu=4*PI*1e-7, E_x0=1,
-        coordinates=None, fixAtBottom=False, tol=1e-8, saveMemory=True, directSolver=False):
-        """
-        initializes a new forward model.
-
-        :param data: real and imaginary part of data
-        :type data: ``Data`` of shape (2,)
-        :param F: real and imaginary part of source given at Dirac points, on surface or at volume.
-        :type F: ``Data`` of shape (2,)
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param omega: frequency
-        :type omega: positive ``float``
-        :param x: coordinates of measurements
-        :type x: ``list`` of ``tuple`` with ``float``
-        :param Z_XY: measured impedance
-        :type Z_XY: ``list`` of ``complex``
-        :param eta: spatial confidence radius
-        :type eta:  positive ``float`` or ``list`` of  positive ``float``
-        :param w0: confidence factors for meassurements. If not set one is assumed.
-        :type w0: ``None`` or a list of positive ``float``
-        :param E_x0: value of E_x at top the domain and if `fixAtBottom` is set at the bottom of the domain.
-        :type E_x0: ``float``, ``complex`` or ``Data`` of shape (2,)
-        :param mu: permeability
-        :type mu: ``float``
-        :param coordinates: defines coordinate system to be used (not supported yet)
-        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        :param fixAtBottom: if true E_x is set E_x0 at the bottom of the domain
-        :type fixAtBottom: ``bool``
-        :param saveMemory: if true stiffness matrix is deleted after solution
-                           of the PDE to minimize memory requests. This will
-                           require more compute time as the matrix needs to be
-                           reallocated.
-        :type saveMemory: ``bool``
-        """
-        super(MT2DModelTEMode, self).__init__()
-        self.__domain = domain
-        DIM=domain.getDim()
-        self.__trafo=makeTranformation(domain, coordinates)
-        if not self.getCoordinateTransformation().isCartesian():
-            raise ValueError("Non-Cartesian coordinates are not supported yet.")
-        self.__omega=omega
-        self.__mu=mu
-
-        #====================================
-        if not len(x) == len(Z_XY):
-            raise ValueError("Number of data points and number of impedance values don't match.")
-        self.__x=x
-        f=-1./(complex(0,1)*omega*mu)
-        self.__scaledZxy=[ z*f for z in Z_XY ]
-        #====================================
-        if isinstance(eta, float) or isinstance(eta, int) :
-            self.__eta =[ float(eta) for z in Z_XY]
-        else:
-            self.__eta =eta
-        if not len(self.__eta) == len(Z_XY):
-                raise ValueError("Number of confidence radii and number of impedance values don't match.")
-        #====================================
-        if isinstance(w0, float) or isinstance(w0, int):
-               w0 =[ float(w0) for z in Z_XY]
-        if not len(w0) == len(Z_XY):
-                raise ValueError("Number of confidence factors and number of impedance values don't match.")
-
-        self.__wx0=[0.] * len(Z_XY)
-        x=Function(domain).getX()
-        totalS=0
-        s = 0
-        while s < len(self.__scaledZxy):
-            totalS+=w0[s]
-            f=integrate(self.getWeightingFactor(x, 1., self.__x[s], self.__eta[s]))
-            if f < 2*PI*self.__eta[s]**2 * 0.1 :
-                raise ValueError("Zero weight (almost) for data point %s. Change eta or refine mesh."%(s,))
-            self.__wx0[s]=w0[s]/f
-            s += 1
-        if not totalS >0 : 
-             raise ValueError("Scaling of weight factors failed as sum is zero.")
-            
-        self.__wx0=[ w/totalS for w in self.__wx0 ]
-        #====================================
-        if isinstance(E_x0, float) or isinstance(E_x0, int) :
-            self.__E_x0 =Data((E_x0,0), Solution(domain))
-        elif isinstance(E_x0, tuple):
-            self.__E_x0 =Data((E_x0[0],E_x0[1]), Solution(domain))
-        elif isinstance(E_x0, complex):
-            self.__E_x0 =Data((E_x0.real,E_x0.imag), Solution(domain))
-        else:
-            if not E_x0.getShape() == (2,):
-                raise ValueError("Expected shape of E_x0 is (2,)")
-            self.__E_x0= E_x0
-        #=======================
-        self.__tol=tol
-        self.__fixAtBottom=fixAtBottom
-        self.__directSolver=directSolver
-        self.__pde=None
-        if not saveMemory:
-            self.__pde=self.setUpPDE()
-
-    def getDomain(self):
-        """
-        Returns the domain of the forward model.
-
-        :rtype: `Domain`
-        """
-        return self.__domain
-
-    def getCoordinateTransformation(self):
-        """
-        returns the coordinate transformation being used
-
-        :rtype: ``CoordinateTransformation``
-        """
-        return self.__trafo
-
-    def setUpPDE(self):
-        """
-        Return the underlying PDE.
-
-        :rtype: `LinearPDE`
-        """
-        if self.__pde is None:
-            pde=LinearPDE(self.__domain, numEquations=2)
-            if(self.__directSolver == True):
-                pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT)
-            D=pde.createCoefficient('D')
-            A=pde.createCoefficient('A')
-            Y=pde.createCoefficient('Y')
-            X=pde.createCoefficient('X')
-            A[0,:,0,:]=kronecker(self.__domain.getDim())
-            A[1,:,1,:]=kronecker(self.__domain.getDim())
-            pde.setValue(A=A, D=D, X=X, Y=Y)
-            DIM=self.__domain.getDim()
-            z = self.__domain.getX()[DIM-1]
-            q=whereZero(z-sup(z))
-            if self.__fixAtBottom:
-                q+=whereZero(z-inf(z))
-            pde.setValue(q=q*[1,1])
-            pde.getSolverOptions().setTolerance(self.__tol)
-            pde.setSymmetryOff()
-        else:
-            pde=self.__pde
-            pde.resetRightHandSideCoefficients()
-        return pde
-
-    def getArguments(self, sigma):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param sigma: conductivity
-        :type sigma: ``Data`` of shape (2,)
-        :return: E_x, E_x,z
-        :rtype: ``Data`` of shape (2,)
-        """
-        pde=self.setUpPDE()
-        D=pde.getCoefficient('D')
-        f=self.__omega * self.__mu * sigma
-        D[0,1]= - f
-        D[1,0]=   f
-        pde.setValue(D=D, r=self.__E_x0)
-        u=pde.getSolution()        
-        return u, grad(u)[:,1]
-
-    def getWeightingFactor(self, x, wx0, x0, eta):
-        """
-        returns the weighting factor
-        """
-        return wx0 * exp(length(x-x0)**2*(-0.5/eta**2))
-
-    def getDefect(self, sigma, E_x, dE_xdz):
-        """
-        Returns the defect value.
-
-        :param sigma: a suggestion for complex 1/V**2
-        :type sigma: ``Data`` of shape (2,)
-        :param E_x: electric field
-        :type E_x: ``Data`` of shape (2,)
-        :param dE_xdz: vertical derivative of electric field
-        :type dE_xdz: ``Data`` of shape (2,)
-
-        :rtype: ``float``
-        """
-        x=Function(self.getDomain()).getX()
-        A=0
-        u0=E_x[0]
-        u1=E_x[1]
-        u01=dE_xdz[0]
-        u11=dE_xdz[1]
-
-        # this cane be done faster!
-        s = 0
-        while s < len(self.__scaledZxy):
-            ws=self.getWeightingFactor(x, self.__wx0[s], self.__x[s], self.__eta[s])
-            A+=integrate( ws * ( (u0-u01*self.__scaledZxy[s].real+u11*self.__scaledZxy[s].imag)**2 + (u1-u01*self.__scaledZxy[s].imag-u11*self.__scaledZxy[s].real)**2 ) )
-            s += 1
-        return  A/2
-
-    def getGradient(self, sigma, E_x, dE_xdz):
-        """
-        Returns the gradient of the defect with respect to density.
-
-        :param sigma: a suggestion for complex 1/V**2
-        :type sigma: ``Data`` of shape (2,)
-        :param E_x: electric field
-        :type E_x: ``Data`` of shape (2,)
-        :param dE_xdz: vertical derivative of electric field
-        :type dE_xdz: ``Data`` of shape (2,)
-        """
-        x=Function(self.getDomain()).getX()
-        pde=self.setUpPDE()
-
-        u0=E_x[0]
-        u1=E_x[1]
-        u01=dE_xdz[0]
-        u11=dE_xdz[1]
-
-        D=pde.getCoefficient('D')
-        Y=pde.getCoefficient('Y')
-        X=pde.getCoefficient('X')
-
-        f=self.__omega * self.__mu * sigma
-        D[0,1]=  f
-        D[1,0]= -f
-
-        s = 0
-        while s < len(self.__scaledZxy):
-            ws=self.getWeightingFactor(x, self.__wx0[s], self.__x[s], self.__eta[s])
-            Y[0]+=ws * (u0 - u01* self.__scaledZxy[s].real + u11* self.__scaledZxy[s].imag)
-            Y[1]+=ws * (u1 - u01* self.__scaledZxy[s].imag - u11* self.__scaledZxy[s].real)
-            X[0,1]+=ws * (u01* abs(self.__scaledZxy[s])**2 - u0* self.__scaledZxy[s].real - u1* self.__scaledZxy[s].imag )
-            X[1,1]+=ws * (u11* abs(self.__scaledZxy[s])**2 + u0* self.__scaledZxy[s].imag - u1* self.__scaledZxy[s].real )
-            s += 1
-        pde.setValue(D=D, X=X, Y=Y)
-        Zstar=pde.getSolution()
-        return self.__omega * self.__mu * (Zstar[0]*u1-Zstar[1]*u0)
-        
-class Subsidence(ForwardModel):
-    """
-    Forward Model for subsidence inversion minimizing integrate( (inner(w,u)-d)**2) 
-    where u is the surface displacement due to a pressure change P 
-    """
-    def __init__(self, domain, w, d, lam, mu, coordinates=None, tol=1e-8):
-        """
-        Creates a new subsidence on the given domain
-
-        :param domain: domain of the model
-        :type domain: `Domain`
-        :param w: data weighting factors and direction 
-        :type w: ``Vector`` with ``FunctionOnBoundary``
-        :param d: displacement measured at surface 
-        :type d: ``Scalar`` with ``FunctionOnBoundary``
-        :param lam: 1st Lame coefficient
-        :type lam: ``Scalar`` with ``Function``
-        :param lam: 2st Lame coefficient/Shear modulus
-        :type lam: ``Scalar`` with ``Function``
-        :param coordinates: defines coordinate system to be used (not supported yet))
-        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
-        :param tol: tolerance of underlying PDE
-        :type tol: positive ``float``
-        """
-        super(Subsidence, self).__init__()
-        DIM=domain.getDim()
-        
-        
-        self.__pde=LinearPDESystem(domain)
-        self.__pde.setSymmetryOn()
-        self.__pde.getSolverOptions().setTolerance(tol)
-        #... set coefficients ...
-        C=self.__pde.createCoefficient('A')
-        for i in range(DIM):
-            for j in range(DIM):
-                C[i,i,j,j]+=lam
-                C[i,j,i,j]+=mu
-                C[i,j,j,i]+=mu
-        x=domain.getX()
-        msk=whereZero(x[DIM-1])*kronecker(DIM)[DIM-1]
-        for i in range(DIM-1):
-            xi=x[i]
-            msk+=(whereZero(xi-inf(xi))+whereZero(xi-sup(xi))) *kronecker(DIM)[i]
-        self.__pde.setValue(A=C,q=msk)
-
-        self.__w=interpolate(w, FunctionOnBoundary(domain))
-        self.__d=interpolate(d, FunctionOnBoundary(domain))
-
-    def rescaleWeights(self, scale=1., P_scale=1.):
-        """
-        rescales the weights such that
-        :param scale: scale of data weighting factors
-        :type scale: positive ``float``
-        :param P_scale: scale of pressure increment
-        :type P_scale: ``Scalar``
-        """
-        pass
-
-    def getArguments(self, P):
-        """
-        Returns precomputed values shared by `getDefect()` and `getGradient()`.
-
-        :param P: pressure
-        :type P: ``Scalar``
-        :return: displacement u
-        :rtype: ``Vector``
-        """
-        DIM=self.__pde.getDim()
-        self.__pde.setValue(y=Data(),X=P*kronecker(DIM))
-        u= self.__pde.getSolution()
-        return u,
-
-    def getDefect(self, P,u):
-        """
-        Returns the value of the defect.
-
-        :param P: pressure
-        :type P: ``Scalar``
-        :param u: corresponding displacement
-        :type u: ``Vector``
-        :rtype: ``float``
-        """
-        return 0.5*integrate((inner(u,self.__w)-self.__d)**2)
-
-    def getGradient(self, P, u):
-        """
-        Returns the gradient of the defect with respect to susceptibility.
-
-        :param P: pressure
-        :type P: ``Scalar``
-        :param u: corresponding displacement
-        :type u: ``Vector``
-        
-        :rtype: ``Scalar``
-        """
-        d=inner(u,self.__w)-self.__d
-        self.__pde.setValue(y=d*self.__w,X=Data())
-        ustar=self.__pde.getSolution()
-
-        return div(ustar)
-            
-
diff --git a/speckley/py_src/__init__.py b/downunder/py_src/forwardmodels/__init__.py
similarity index 65%
copy from speckley/py_src/__init__.py
copy to downunder/py_src/forwardmodels/__init__.py
index 8b72762..619f5e2 100644
--- a/speckley/py_src/__init__.py
+++ b/downunder/py_src/forwardmodels/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,18 +14,21 @@
 #
 ##############################################################################
 
-"""A domain meshed with uniform rectangles or quadrilaterals
-"""
+"""Collection of forward models that define the inversion problem"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
 http://www.opensource.org/licenses/osl-3.0.php"""
 __url__="https://launchpad.net/escript-finley"
 
-import esys.escript		# This is just to ensure required libraries are loaded
-from .speckleycpp import *
+from .base import *
+from .acoustic import *
+from .dcresistivity import *
+from .gravity import *
+from .magnetic import *
+from .magnetotelluric2d import *
+from .pressure import *
+from .subsidence import *
 
-
-__nodocorecursion=['speckleycpp']
diff --git a/downunder/py_src/forwardmodels/acoustic.py b/downunder/py_src/forwardmodels/acoustic.py
new file mode 100644
index 0000000..2640ff8
--- /dev/null
+++ b/downunder/py_src/forwardmodels/acoustic.py
@@ -0,0 +1,319 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Forward model for acoustic wave forms"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['AcousticWaveForm']
+
+from .base import ForwardModel
+from esys.downunder.coordinates import makeTranformation
+from esys.escript import Data, DiracDeltaFunctions, FunctionOnBoundary
+from esys.escript.linearPDEs import LinearPDE, SolverOptions
+from esys.escript.util import *
+import numpy as np
+
+
+class AcousticWaveForm(ForwardModel):
+    """
+    Forward Model for acoustic waveform inversion in the frequency domain.
+    It defines a cost function:
+
+    :math: `defect = 1/2 integrate( ( w * ( a * u - data ) ) ** 2 )`
+
+    where w are weighting factors, data are the measured data (as a 2-comp
+    vector of real and imaginary part) for real frequency omega, and u is
+    the corresponding result produced by the forward model.
+    u (as a 2-comp vector) is the solution of the complex Helmholtz equation
+    for frequency omega, source F and complex, inverse, squared p-velocity
+    sigma:
+
+    :math: `-u_{ii} - omega**2 * sigma * u = F`
+
+    It is assumed that the exact scale of source F is unknown and the scaling
+    factor a of F is calculated by minimizing the defect.
+    """
+    def __init__(self, domain, omega, w, data, F, coordinates=None,
+                 fixAtBottom=False, tol=1e-8, saveMemory=True, scaleF=True):
+        """
+        initializes a new forward model with acoustic wave form inversion.
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param w: weighting factors
+        :type w: ``Scalar``
+        :param data: real and imaginary part of data
+        :type data: ``Data`` of shape (2,)
+        :param F: real and imaginary part of source given at Dirac points,
+                  on surface or at volume.
+        :type F: ``Data`` of shape (2,)
+        :param coordinates: defines coordinate system to be used (not supported yet)
+        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        :param saveMemory: if true stiffness matrix is deleted after solution
+                           of PDE to minimize memory requests. This will
+                           require more compute time as the matrix needs to be
+                           reallocated.
+        :type saveMemory: ``bool``
+        :param scaleF: if true source F is scaled to minimize defect.
+        :type scaleF: ``bool``
+        :param fixAtBottom: if true pressure is fixed to zero at the bottom of
+                            the domain
+        :type fixAtBottom: ``bool``
+        """
+        super(AcousticWaveForm, self).__init__()
+        self.__trafo = makeTranformation(domain, coordinates)
+        if not self.getCoordinateTransformation().isCartesian():
+            raise ValueError("Non-Cartesian Coordinates are not supported yet.")
+        if not isinstance(data, Data):
+            raise ValueError("data must be an escript.Data object.")
+        if not data.getFunctionSpace() == FunctionOnBoundary(domain):
+            raise ValueError("data must be defined on boundary")
+        if not data.getShape() == (2,):
+            raise ValueError("data must have shape (2,) (real and imaginary part).")
+        if w is None:
+            w = 1.
+        if not isinstance(w, Data):
+            w = Data(w, FunctionOnBoundary(domain))
+        else:
+            if not w.getFunctionSpace() == FunctionOnBoundary(domain):
+                raise ValueError("Weights must be defined on boundary.")
+            if not w.getShape() == ():
+                raise ValueError("Weights must be scalar.")
+
+        self.__domain = domain
+        self.__omega = omega
+        self.__weight = w
+        self.__data = data
+        self.scaleF = scaleF
+        if scaleF:
+            A = integrate(self.__weight*length(self.__data)**2)
+            if A > 0:
+                self.__data*=1./sqrt(A)
+
+        self.__BX = boundingBox(domain)
+        self.edge_lengths = np.asarray(boundingBoxEdgeLengths(domain))
+
+        if not isinstance(F, Data):
+            F=interpolate(F,  DiracDeltaFunctions(domain))
+        if not F.getShape() == (2,):
+            raise ValueError("Source must have shape (2,) (real and imaginary part).")
+
+        self.__F=Data()
+        self.__f=Data()
+        self.__f_dirac=Data()
+
+        if F.getFunctionSpace() == DiracDeltaFunctions(domain):
+            self.__f_dirac=F
+        elif F.getFunctionSpace() == FunctionOnBoundary(domain):
+            self.__f=F
+        else:
+            self.__F=F
+        self.__tol=tol
+        self.__fixAtBottom=fixAtBottom
+        self.__pde=None
+        if not saveMemory:
+            self.__pde=self.setUpPDE()
+
+    def getSurvey(self, index=None):
+        """
+        Returns the pair (data, weight)
+
+        If argument index is ignored.
+        """
+        return self.__data, self.__weight
+
+    def rescaleWeights(self, scale=1., sigma_scale=1.):
+        """
+        rescales the weights such that
+
+        :math: integrate( ( w omega**2 * sigma_scale * data * ((1/L_j)**2)**-1) +1 )/(data*omega**2 * ((1/L_j)**2)**-1) * sigma_scale )=scale
+
+        :param scale: scale of data weighting factors
+        :type scale: positive ``float``
+        :param sigma_scale: scale of 1/vp**2 velocity.
+        :type sigma_scale: ``Scalar``
+        """
+        raise Warning("rescaleWeights is not tested yet.")
+        if not scale > 0:
+            raise ValueError("Value for scale must be positive.")
+        if not sigma_scale*omega**2*d > 0:
+            raise ValueError("Rescaling of weights failed due to zero denominator.")
+        # copy back original weights before rescaling
+        #self.__weight=[1.*ow for ow in self.__origweight]
+        L2=1/length(1/self.edge_length)**2
+        d=Lsup(length(data))
+        A=integrate(self.__weight*(sigma_scale*omega**2*d+1)/(sigma_scale*omega**2*d) )
+        if A > 0:
+            self.__weight*=1./A
+            if self.scaleF:
+                self.__data*=sqrt(A)
+        else:
+            raise ValueError("Rescaling of weights failed.")
+
+    def getDomain(self):
+        """
+        Returns the domain of the forward model.
+
+        :rtype: `Domain`
+        """
+        return self.__domain
+
+    def getCoordinateTransformation(self):
+        """
+        returns the coordinate transformation being used
+
+        :rtype: ``CoordinateTransformation``
+        """
+        return self.__trafo
+
+    def setUpPDE(self):
+        """
+        Creates and returns the underlying PDE.
+
+        :rtype: `LinearPDE`
+        """
+        from esys.escript import getEscriptParamInt
+        if self.__pde is None:
+            if getEscriptParamInt("PASO_DIRECT")==0:
+                raise ValueError("Either this build of escript or the current MPI configuration does not support direct solvers.")
+            pde=LinearPDE(self.__domain, numEquations=2)
+            D=pde.createCoefficient('D')
+            A=pde.createCoefficient('A')
+            A[0,:,0,:]=kronecker(self.__domain.getDim())
+            A[1,:,1,:]=kronecker(self.__domain.getDim())
+            pde.setValue(A=A, D=D)
+            if self.__fixAtBottom:
+                DIM=self.__domain.getDim()
+                z = self.__domain.getX()[DIM-1]
+                pde.setValue(q=whereZero(z-self.__BX[DIM-1][0])*[1,1])
+
+            pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT)
+            pde.getSolverOptions().setTolerance(self.__tol)
+            pde.setSymmetryOff()
+        else:
+            pde=self.__pde
+            pde.resetRightHandSideCoefficients()
+        return pde
+
+    def getSourceScaling(self, u):
+        """
+        returns the scaling factor s required to rescale source F to minimize defect ``|s * u- data|^2``
+
+        :param u: value of pressure solution (real and imaginary part)
+        :type u: ``Data`` of shape (2,)
+        :rtype: `complex`
+        """
+        uTu = integrate(self.__weight * length(u)**2)
+        uTar = integrate(self.__weight * ( u[0]*self.__data[0]+u[1]*self.__data[1]) )
+        uTai = integrate(self.__weight * ( u[0]*self.__data[1]-u[1]*self.__data[0]) )
+        if uTu > 0:
+            return complex(uTar/uTu, uTai/uTu)
+        else:
+            return complex(1.,0)
+
+    def getArguments(self, sigma):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param sigma: a suggestion for complex 1/V**2
+        :type sigma: ``Data`` of shape (2,)
+        :return: solution,  uTar, uTai, uTu
+        :rtype: ``Data`` of shape (2,), 3 x `float`
+        """
+        pde=self.setUpPDE()
+        D=pde.getCoefficient('D')
+        D[0,0]=-self.__omega**2 * sigma[0]
+        D[0,1]= self.__omega**2 * sigma[1]
+        D[1,0]=-self.__omega**2 * sigma[1]
+        D[1,1]=-self.__omega**2 * sigma[0]
+        pde.setValue(D=D, Y=self.__F, y=self.__f, y_dirac=self.__f_dirac)
+        u=pde.getSolution()
+
+        uTar=integrate(self.__weight * ( u[0]*self.__data[0]+u[1]*self.__data[1]) )
+        uTai=integrate(self.__weight * ( u[0]*self.__data[1]-u[1]*self.__data[0]) )
+        uTu = integrate( self.__weight * length(u)**2 )
+        return u, uTar, uTai, uTu
+
+    def getDefect(self, sigma, u, uTar, uTai, uTu):
+        """
+        Returns the defect value.
+
+        :param sigma: a suggestion for complex 1/V**2
+        :type sigma: ``Data`` of shape (2,)
+        :param u: a u vector
+        :type u: ``Data`` of shape (2,)
+        :param uTar: equals `integrate( w  * (data[0]*u[0]+data[1]*u[1]))`
+        :type uTar: `float`
+        :param uTai: equals `integrate( w  * (data[1]*u[0]-data[0]*u[1]))`
+        :type uTa: `float`
+        :param uTu: equals `integrate( w  * (u,u))`
+        :type uTu: `float`
+
+        :rtype: ``float``
+        """
+        # assuming integrate(w * length(data)**2) =1
+        if self.scaleF and abs(uTu) >0:
+           A = 1.-(uTar**2 + uTai**2)/uTu
+        else:
+           A = integrate(self.__weight*length(self.__data)**2)- 2 * uTar + uTu
+        return  A/2
+
+    def getGradient(self, sigma, u, uTar, uTai, uTu):
+        """
+        Returns the gradient of the defect with respect to density.
+
+        :param sigma: a suggestion for complex 1/V**2
+        :type sigma: ``Data`` of shape (2,)
+        :param u: a u vector
+        :type u: ``Data`` of shape (2,)
+        :param uTar: equals `integrate( w  * (data[0]*u[0]+data[1]*u[1]))`
+        :type uTar: `float`
+        :param uTai: equals `integrate( w  * (data[1]*u[0]-data[0]*u[1]))`
+        :type uTa: `float`
+        :param uTu: equals `integrate( w  * (u,u))`
+        :type uTu: `float`
+        """
+        pde=self.setUpPDE()
+
+        if self.scaleF and abs(uTu) >0:
+            Z=((uTar**2+uTai**2)/uTu**2) *interpolate(u, self.__data.getFunctionSpace())
+            Z[0]+= (-uTar/uTu) * self.__data[0]+ (-uTai/uTu) * self.__data[1]
+            Z[1]+= (-uTar/uTu) * self.__data[1]+   uTai/uTu  * self.__data[0]
+
+        else:
+            Z = u - self.__data
+        if Z.getFunctionSpace() == DiracDeltaFunctions(self.getDomain()):
+            pde.setValue(y_dirac=self.__weight * Z)
+        else:
+            pde.setValue(y=self.__weight * Z)
+        D=pde.getCoefficient('D')
+        D[0,0]=-self.__omega**2 * sigma[0]
+        D[0,1]=-self.__omega**2 * sigma[1]
+        D[1,0]= self.__omega**2 * sigma[1]
+        D[1,1]=-self.__omega**2 * sigma[0]
+        pde.setValue(D=D)
+        ZTo2=pde.getSolution()*self.__omega**2
+        return inner(ZTo2,u)*[1,0]+(ZTo2[1]*u[0]-ZTo2[0]*u[1])*[0,1]
+
diff --git a/downunder/py_src/forwardmodels/base.py b/downunder/py_src/forwardmodels/base.py
new file mode 100644
index 0000000..fe94a72
--- /dev/null
+++ b/downunder/py_src/forwardmodels/base.py
@@ -0,0 +1,206 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Base classes for forward models"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['ForwardModel','ForwardModelWithPotential']
+
+from esys.downunder.coordinates import makeTranformation
+from esys.escript.linearPDEs import LinearSinglePDE
+from esys.escript.util import *
+import numpy as np
+
+class ForwardModel(object):
+    """
+    An abstract forward model that can be plugged into a cost function.
+    Subclasses need to implement `getDefect()`, `getGradient()`, and possibly
+    `getArguments()` and 'getCoordinateTransformation'.
+    """
+    def __init__(self):
+        pass
+
+    def getArguments(self, x):
+        return ()
+
+    def getCoordinateTransformation(self):
+        return None
+
+    def getDefect(self, x, *args):
+        raise NotImplementedError
+
+    def getGradient(self, x, *args):
+        raise NotImplementedError
+
+
+class ForwardModelWithPotential(ForwardModel):
+    """
+    Base class for a forward model using a potential such as magnetic or
+    gravity. It defines a cost function:
+
+        defect = 1/2 sum_s integrate( ( weight_i[s] * ( r_i - data_i[s] ) )**2 )
+
+    where s runs over the survey, weight_i are weighting factors, data_i are
+    the data, and r_i are the results produced by the forward model.
+    It is assumed that the forward model is produced through postprocessing
+    of the solution of a potential PDE.
+    """
+    def __init__(self, domain, w, data,  coordinates=None,
+                                 fixPotentialAtBottom=False,
+                                 tol=1e-8):
+        """
+        initializes a new forward model with potential.
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param w: data weighting factors
+        :type w: ``Vector`` or list of ``Vector``
+        :param data: data
+        :type data: ``Vector`` or list of ``Vector``
+        :param coordinates: defines coordinate system to be used
+        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param fixPotentialAtBottom: if true potential is fixed to zero at the bottom of the domain
+                                     in addition to the top.
+        :type fixPotentialAtBottom: ``bool``
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        """
+        super(ForwardModelWithPotential, self).__init__()
+        self.__domain = domain
+        self.__trafo = makeTranformation(domain, coordinates)
+
+        try:
+            n=len(w)
+            m=len(data)
+            if not m == n:
+                raise ValueError("Length of weight and data must be the same.")
+            self.__weight = w
+            self.__data = data
+        except TypeError:
+            self.__weight = [w]
+            self.__data = [data]
+
+        BX = boundingBox(domain)
+        DIM = domain.getDim()
+        x = domain.getX()
+        self.__pde=LinearSinglePDE(domain)
+        self.__pde.getSolverOptions().setTolerance(tol)
+        self.__pde.setSymmetryOn()
+        z=x[DIM-1]
+        q0=whereZero(z-BX[DIM-1][1])
+        if fixPotentialAtBottom: q0+=whereZero(z-BX[DIM-1][0])
+        self.__pde.setValue(q=q0)
+
+        self.edge_lengths=np.asarray(boundingBoxEdgeLengths(domain))
+        self.diameter=1./sqrt(sum(1./self.edge_lengths**2))
+
+        self.__origweight=[]
+        for s in range(len(self.__weight)):
+            # save a copy of the original weights in case of rescaling
+            self.__origweight.append(1.*self.__weight[s])
+
+        if not self.__trafo.isCartesian():
+            fd=1./self.__trafo.getScalingFactors()
+            fw=self.__trafo.getScalingFactors()*sqrt(self.__trafo.getVolumeFactor())
+            for s in range(len(self.__weight)):
+                self.__weight[s] = fw * self.__weight[s]
+                self.__data[s]   = fd * self.__data[s]
+
+    def _rescaleWeights(self, scale=1., fetch_factor=1.):
+        """
+        rescales the weights such that
+
+        *sum_s integrate( ( weight_i[s] *data_i[s]) (weight_j[s]*1/L_j) * L**2 * fetch_factor )=scale*
+        """
+        if not scale > 0:
+             raise ValueError("Value for scale must be positive.")
+        A=0
+        # copy back original weights before rescaling
+        self.__weight=[1.*ow for ow in self.__origweight]
+
+        for s in range(len(self.__weight)):
+            A += integrate(abs(inner(self.__weight[s], self.__data[s]) * inner(self.__weight[s], 1/self.edge_lengths) * fetch_factor))
+        if A > 0:
+            A=sqrt(scale/A)/self.diameter
+            if not self.__trafo.isCartesian():
+                A*=self.__trafo.getScalingFactors()*sqrt(self.__trafo.getVolumeFactor())
+            for s in range(len(self.__weight)):
+                self.__weight[s]*=A
+        else:
+            raise ValueError("Rescaling of weights failed.")
+
+    def getDomain(self):
+        """
+        Returns the domain of the forward model.
+
+        :rtype: `Domain`
+        """
+        return self.__domain
+
+    def getCoordinateTransformation(self):
+        """
+        returns the coordinate transformation being used
+
+        :rtype: ``CoordinateTransformation``
+        """
+        return self.__trafo
+
+    def getPDE(self):
+        """
+        Return the underlying PDE.
+
+        :rtype: `LinearPDE`
+        """
+        return self.__pde
+
+    def _getDefect(self, result):
+        """
+        Returns the defect value.
+
+        :param result: a result vector
+        :type result: `Vector`
+        :rtype: ``float``
+        """
+        A=0.
+        for s in range(len(self.__weight)):
+            A += integrate( inner(self.__weight[s], self.__data[s]-result)**2 )
+        return A/2
+
+    def getDefectGradient(self, result):
+        Y=0.
+        for s in range(len(self.__weight)):
+            Y = inner(self.__weight[s], self.__data[s]-result) * self.__weight[s] + Y
+        return Y
+
+    def getSurvey(self, index=None):
+        """
+        Returns the pair (data_index, weight_index), where data_i is the data
+        of survey i, weight_i is the weighting factor for survey i.
+        If index is None, all surveys will be returned in a pair of lists.
+        """
+        if index is None:
+            return self.__data, self.__weight
+        if index>=len(self.__data):
+            raise IndexError("Forward model only has %d surveys"%len(self.__data))
+        return self.__data[index], self.__weight[index]
+
diff --git a/downunder/py_src/forwardmodels/dcresistivity.py b/downunder/py_src/forwardmodels/dcresistivity.py
new file mode 100644
index 0000000..d39f4a6
--- /dev/null
+++ b/downunder/py_src/forwardmodels/dcresistivity.py
@@ -0,0 +1,260 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Forward model for DC Resistivity"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['DcRes']
+
+from .base import ForwardModel
+from esys.downunder.coordinates import makeTranformation
+from esys.escript import Scalar, DiracDeltaFunctions
+from esys.escript.pdetools import Locator
+from esys.escript.linearPDEs import LinearPDE
+from esys.escript.util import *
+
+
+class DcRes(ForwardModel):
+    """
+    Forward Model for DC resistivity, with a given source pair.
+    The cost function is defined as:
+
+    :math: defect = 1/2 (sum_s sum_pq w_pqs * ((phi_sp-phi_sq)-v_pqs)**2
+
+    """
+    def __init__(self, domain, locator, delphiIn, sampleTags, phiPrimary,
+                 sigmaPrimary, w=1., coordinates=None, tol=1e-8,
+                 saveMemory=True, b=None):
+        """
+        setup new forward model
+        
+        :param domain: the domain of the model
+        :type: escript domain
+        :param locator: contains locator to the measurement pairs
+        :type: `list` of ``Locator``
+        :param: delphiIn: this is v_pq, the potential difference for the
+                          current source and a set of measurement pairs.
+                          A list of measured potential differences is expected.
+                          Note this should be the secondary potential only.
+        :type delphiIn: tuple
+        :param sampleTags: tags of measurement points from which potential
+                           differences will be calculated.
+        :type sampleTags: list of tuples
+        :param phiPrimary: primary potential.
+        :type phiPrimary: `Scalar`
+        """
+        super(DcRes, self).__init__()
+
+        if not isinstance(sampleTags, list):
+            raise ValueError("sampleTags must be a list.")
+        if not len(sampleTags) == len(delphiIn):
+            raise ValueError("sampleTags and delphiIn must have the same length.")
+        if not len(sampleTags)>0:
+            raise ValueError("sampleTags list is empty.")
+        if not isinstance(sampleTags[0], tuple) and not isinstance(sampleTags[0], list):
+            raise ValueError("sampleTags must be a list of tuples or a list of lists.")
+
+        if isinstance(w, float) or isinstance(w, int):
+            w = [float(w) for z in delphiIn]
+            self.__w = w
+        else:
+            self.__w = w
+        if not len(w) == len(delphiIn):
+            raise ValueError("Number of confidence factors and number of potential input values don't match.")
+
+        self.__trafo = makeTranformation(domain, coordinates)
+        if not self.getCoordinateTransformation().isCartesian():
+            raise ValueError("Non-Cartesian Coordinates are not supported yet.")
+        if not isinstance(locator, Locator):
+            raise ValueError("locator must be an escript locator object")
+
+        self.__domain = domain
+        self.__tol = tol
+        self.__locator = locator
+        self.delphiIn = delphiIn
+        self.__sampleTags = sampleTags
+        self.__sigmaPrimary = sigmaPrimary
+        self.__phiPrimary = phiPrimary
+        self.__pde = None
+        if not saveMemory:
+            self.__pde=self.setUpPDE()
+
+    def getDomain(self):
+        """
+        Returns the domain of the forward model.
+
+        :rtype: `Domain`
+        """
+        return self.__domain
+
+    def getCoordinateTransformation(self):
+        """
+        returns the coordinate transformation being used
+
+        :rtype: ``CoordinateTransformation``
+        """
+        return self.__trafo
+
+    def getPrimaryPotential(self):
+        """
+        returns the primary potential
+        :rtype: `Data`
+        """
+        return self.__phiPrimary
+
+    def setUpPDE(self):
+        """
+        Return the underlying PDE.
+
+        :rtype: `LinearPDE`
+        """
+        if self.__pde is None:
+            dom=self.__domain
+            x = dom.getX()
+            DIM=dom.getDim()
+            q=whereZero(x[DIM-1]-inf(x[DIM-1]))
+            for i in range(DIM-1):
+                xi=x[i]
+                q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
+
+            pde=LinearPDE(dom, numEquations=1)
+            pde.getSolverOptions().setTolerance(self.__tol)
+            pde.setSymmetryOn()
+            A=pde.createCoefficient('A')
+            X=pde.createCoefficient('X')
+            pde.setValue(A=A, X=X, q=q)
+
+        else:
+            pde=self.__pde
+            pde.resetRightHandSideCoefficients()
+        return pde
+
+    def getArguments(self, sigma):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param sigma: conductivity
+        :type sigma: ``Data`` of shape (1,)
+        :return: phi
+        :rtype: ``Data`` of shape (1,)
+        """
+        pde = self.setUpPDE()
+        X = (self.__sigmaPrimary - sigma) * grad(self.__phiPrimary)
+        pde.setValue(A=sigma * kronecker(self.__domain), X=X)
+        phi = pde.getSolution()
+        loc = self.__locator
+        loc_phi = loc.getValue(phi)
+        return phi, loc_phi
+
+    def getDefect(self, sigma, phi, loc_phi):
+        """
+        Returns the defect value.
+
+        :param sigma: a suggestion for conductivity
+        :type sigma: ``Data`` of shape (1,)
+        :param phi: potential field
+        :type phi: ``Data`` of shape (1,)
+        :rtype: ``float``
+        """
+        val=loc_phi
+        if not isinstance(val,list):
+            tmp=val
+            val=[tmp]
+        # print "val=",val
+        length=len(val)
+        # print self.__sampleTags[0]
+        if ((self.__sampleTags[0][1]!="-" and (length%2) != 0) or \
+                (self.__sampleTags[0][1]!="-" and length/2 != len(self.delphiIn))):
+            raise ValueError("length of locator is wrong")
+
+        delphi_calc=[]
+        if self.__sampleTags[0][1] != "-":
+            for i in range(0,length,2):
+                delphi_calc.append(val[i+1]-val[i])
+        else:
+            for i in range(length):
+                delphi_calc.append(val[i])
+        A=0
+        if (self.__sampleTags[0][1] != "-"):
+            for i in range(length//2):
+                A += (self.__w[i]*(delphi_calc[i]-self.delphiIn[i])**2)
+        else:
+            for i in range(length):
+                A += (self.__w[i]*(delphi_calc[i]-self.delphiIn[i])**2)
+        return  A/2
+
+    def getGradient(self, sigma, phi, loc_phi):
+        """
+        Returns the gradient of the defect with respect to density.
+
+        :param sigma: a suggestison for conductivity
+        :type sigma: ``Data`` of shape (1,)
+        :param phi: potential field
+        :type phi: ``Data`` of shape (1,)
+        """
+        val=loc_phi
+        if not isinstance(val,list):
+            tmp=val
+            val=[tmp]
+        sampleTags=self.__sampleTags
+
+        jointSamples={}
+        for i in range(0,2*len(sampleTags),2): #2*len because sample tags is a list of tuples
+            half = i//2
+            if sampleTags[half][1]!="-":
+                tmp=(val[i+1]-val[i]-self.delphiIn[half])*self.__w[i]
+            else:
+                tmp=(val[i]-self.delphiIn[i//2]) *self.__w[i]
+            sample = sampleTags[half]
+            if sample[1]!="-":
+                if sample[0] in jointSamples.keys():
+                    jointSamples[sample[0]].append((sample[1], -tmp))
+                else:
+                    jointSamples[sampleTags[half][0]]=[(sample[1],-tmp)]
+                if sample[1] in jointSamples.keys():
+                    jointSamples[sample[1]].append((sample[0], tmp))
+                else:
+                    jointSamples[sample[1]]=[(sample[0], tmp)]
+            else:
+                if sample[0] in jointSamples.keys():
+                    jointSamples[sample[0]].append((sample[1], tmp))
+                else:
+                    jointSamples[sampleTags[half][0]]=[(sample[1],tmp)]
+
+        pde =self.setUpPDE()
+        dom=self.__domain
+        # conPrimary=self.__sigmaPrimary
+        # APrimary = conPrimary * kronecker(dom)
+
+        y_dirac = Scalar(0,DiracDeltaFunctions(dom))
+        for i in jointSamples:
+            total=0
+            for j in jointSamples[i]:
+                total+=j[1]
+            y_dirac.setTaggedValue(i,total)
+
+        pde.setValue(A=sigma*kronecker(dom), y_dirac=y_dirac)
+        u=pde.getSolution()
+        retVal=-inner(grad(u),grad(phi+self.__phiPrimary))
+        return retVal
+
diff --git a/downunder/py_src/forwardmodels/gravity.py b/downunder/py_src/forwardmodels/gravity.py
new file mode 100644
index 0000000..e9691f1
--- /dev/null
+++ b/downunder/py_src/forwardmodels/gravity.py
@@ -0,0 +1,151 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Forward model for gravity (Bouguer) anomaly"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['GravityModel']
+
+from .base import ForwardModelWithPotential
+from esys.escript import unitsSI as U
+from esys.escript.util import *
+from math import pi as PI
+
+
+class GravityModel(ForwardModelWithPotential):
+    """
+    Forward Model for gravity inversion as described in the inversion
+    cookbook.
+    """
+    def __init__(self, domain, w, g, gravity_constant=U.Gravitational_Constant,
+                  coordinates=None, fixPotentialAtBottom=False, tol=1e-8):
+        """
+        Creates a new gravity model on the given domain with one or more
+        surveys (w, g).
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param w: data weighting factors
+        :type w: ``Vector`` or list of ``Vector``
+        :param g: gravity anomaly data
+        :type g: ``Vector`` or list of ``Vector``
+        :param coordinates: defines coordinate system to be used
+        :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        :param fixPotentialAtBottom: if true potential is fixed to zero at the
+                                     base of the domain in addition to the top
+        :type fixPotentialAtBottom: ``bool``
+
+        :note: It is advisable to call rescaleWeights() to rescale weights
+               before starting the inversion.
+        """
+        super(GravityModel, self).__init__(domain, w, g, coordinates, fixPotentialAtBottom, tol)
+
+        trafo = self.getCoordinateTransformation()
+        if not trafo.isCartesian():
+            self.__G = 4*PI*gravity_constant * trafo.getVolumeFactor()
+                    #* trafo.getReferenceSystem().getHeightUnit()**(-3)
+
+            fw = trafo.getScalingFactors()**2 * trafo.getVolumeFactor()
+            A=self.getPDE().createCoefficient("A")
+            for i in range(self.getDomain().getDim()): A[i,i]=fw[i]
+            self.getPDE().setValue(A=A)
+        else: # cartesian
+            self.__G = 4*PI*gravity_constant
+            self.getPDE().setValue(A=kronecker(self.getDomain()))
+
+    def rescaleWeights(self, scale=1., rho_scale=1.):
+        """
+        rescales the weights such that
+
+        *sum_s integrate( ( w_i[s] *g_i[s]) (w_j[s]*1/L_j) * L**2 * 4*pi*G*rho_scale )=scale*
+
+        :param scale: scale of data weighting factors
+        :type scale: positive ``float``
+        :param rho_scale: scale of density.
+        :type rho_scale: ``Scalar``
+        """
+        self._rescaleWeights(scale, self.__G*rho_scale)
+
+    def getArguments(self, rho):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param rho: a suggestion for the density distribution
+        :type rho: ``Scalar``
+        :return: gravity potential and corresponding gravity field.
+        :rtype: ``Scalar``, ``Vector``
+        """
+        phi = self.getPotential(rho)
+        gravity_force = -grad(phi)
+        return phi, gravity_force
+
+    def getPotential(self, rho):
+        """
+        Calculates the gravity potential for a given density distribution.
+
+        :param rho: a suggestion for the density distribution
+        :type rho: ``Scalar``
+        :return: gravity potential
+        :rtype: ``Scalar``
+        """
+        pde = self.getPDE()
+        pde.resetRightHandSideCoefficients()
+        pde.setValue(Y=-self.__G*rho)
+        phi=pde.getSolution()
+
+        return phi
+
+    def getDefect(self, rho, phi, gravity_force):
+        """
+        Returns the value of the defect
+
+        :param rho: density distribution
+        :type rho: ``Scalar``
+        :param phi: corresponding potential
+        :type phi: ``Scalar``
+        :param gravity_force: gravity force
+        :type gravity_force: ``Vector``
+        :rtype: ``float``
+        """
+        return self._getDefect(gravity_force)
+
+    def getGradient(self, rho, phi, gravity_force):
+        """
+        Returns the gradient of the defect with respect to density.
+
+        :param rho: density distribution
+        :type rho: ``Scalar``
+        :param phi: corresponding potential
+        :type phi: ``Scalar``
+        :param gravity_force: gravity force
+        :type gravity_force: ``Vector``
+        :rtype: ``Scalar``
+        """
+        pde=self.getPDE()
+        pde.resetRightHandSideCoefficients()
+        pde.setValue(X=self.getDefectGradient(gravity_force))
+        ZT=pde.getSolution()
+        return ZT*(-self.__G)
+
diff --git a/downunder/py_src/forwardmodels/magnetic.py b/downunder/py_src/forwardmodels/magnetic.py
new file mode 100644
index 0000000..e3ddd81
--- /dev/null
+++ b/downunder/py_src/forwardmodels/magnetic.py
@@ -0,0 +1,302 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Forward models for magnetic fields"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['MagneticModel', 'SelfDemagnetizationModel']
+
+from .base import ForwardModelWithPotential
+from esys.escript.util import *
+
+
+class MagneticModel(ForwardModelWithPotential):
+    """
+    Forward Model for magnetic inversion as described in the inversion
+    cookbook.
+    """
+    def __init__(self, domain, w, B, background_magnetic_flux_density,
+                 coordinates=None, fixPotentialAtBottom=False, tol=1e-8):
+        """
+        Creates a new magnetic model on the given domain with one or more
+        surveys (w, B).
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param w: data weighting factors
+        :type w: ``Vector`` or list of ``Vector``
+        :param B: magnetic field data
+        :type B: ``Vector`` or list of ``Vector``
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        :param background_magnetic_flux_density: background magnetic flux
+               density (in Tesla) with components (B_east, B_north, B_vertical)
+        :type background_magnetic_flux_density: ``Vector`` or list of `float`
+        :param coordinates: defines coordinate system to be used
+        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param fixPotentialAtBottom: if true potential is fixed to zero at the
+                                     bottom of the domain in addition to the top
+        :type fixPotentialAtBottom: ``bool``
+        """
+        super(MagneticModel, self).__init__(domain, w, B, coordinates, fixPotentialAtBottom, tol)
+        background_magnetic_flux_density=interpolate(background_magnetic_flux_density, B[0].getFunctionSpace())
+        if not self.getCoordinateTransformation().isCartesian():
+            s = self.getCoordinateTransformation().getScalingFactors()
+            v = self.getCoordinateTransformation().getVolumeFactor()
+            self.__B_r = background_magnetic_flux_density * s * v
+            self.__B_b = background_magnetic_flux_density / s
+
+            A = self.getPDE().createCoefficient("A")
+            fw = s**2 * v
+            for i in range(self.getDomain().getDim()):
+                A[i,i]=fw[i]
+            self.getPDE().setValue(A=A)
+        else: # cartesian
+            self.getPDE().setValue(A=kronecker(self.getDomain()))
+            self.__B_r = background_magnetic_flux_density
+            self.__B_b = background_magnetic_flux_density
+
+    def rescaleWeights(self, scale=1., k_scale=1.):
+        """
+        rescales the weights such that
+
+        *sum_s integrate( ( w_i[s] *B_i[s]) (w_j[s]*1/L_j) * L**2 * (background_magnetic_flux_density_j[s]*1/L_j) * k_scale )=scale*
+
+        :param scale: scale of data weighting factors
+        :type scale: positive ``float``
+        :param k_scale: scale of susceptibility.
+        :type k_scale: ``Scalar``
+        """
+        self._rescaleWeights(scale, inner(self.__B_r,1/self.edge_lengths ) * k_scale)
+
+    def getArguments(self, k):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :return: scalar magnetic potential and corresponding magnetic field
+        :rtype: ``Scalar``, ``Vector``
+        """
+        phi = self.getPotential(k)
+        magnetic_flux_density = k * self.__B_b -grad(phi)
+        return phi, magnetic_flux_density
+
+    def getPotential(self, k):
+        """
+        Calculates the magnetic potential for a given susceptibility.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :return: magnetic potential
+        :rtype: ``Scalar``
+        """
+        pde=self.getPDE()
+        pde.resetRightHandSideCoefficients()
+        pde.setValue(X = k* self.__B_r)
+        phi=pde.getSolution()
+
+        return phi
+
+    def getDefect(self, k, phi, magnetic_flux_density):
+        """
+        Returns the value of the defect.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :param phi: corresponding potential
+        :type phi: ``Scalar``
+        :param magnetic_flux_density: magnetic field
+        :type magnetic_flux_density: ``Vector``
+        :rtype: ``float``
+        """
+        return self._getDefect(magnetic_flux_density)
+
+    def getGradient(self, k, phi, magnetic_flux_density):
+        """
+        Returns the gradient of the defect with respect to susceptibility.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :param phi: corresponding potential
+        :type phi: ``Scalar``
+        :param magnetic_flux_density: magnetic field
+        :type magnetic_flux_density: ``Vector``
+        :rtype: ``Scalar``
+        """
+        Y=self.getDefectGradient(magnetic_flux_density)
+        pde=self.getPDE()
+        pde.resetRightHandSideCoefficients()
+        pde.setValue(X=Y)
+        YT=pde.getSolution()
+        return inner(grad(YT),self.__B_r) -inner(Y,self.__B_b)
+
+class SelfDemagnetizationModel(ForwardModelWithPotential):
+    """
+    Forward Model for magnetic inversion with self-demagnetization as
+    described in the inversion cookbook.
+    """
+    def __init__(self, domain, w, B, background_magnetic_flux_density,
+                 coordinates=None, fixPotentialAtBottom=False, tol=1e-8):
+        """
+        Creates a new magnetic model on the given domain with one or more
+        surveys (w, B).
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param w: data weighting factors
+        :type w: ``Vector`` or list of ``Vector``
+        :param B: magnetic field data
+        :type B: ``Vector`` or list of ``Vector``
+        :param background_magnetic_flux_density: background magnetic flux
+               density (in Tesla) with components (B_east, B_north, B_vertical)
+        :type background_magnetic_flux_density: ``Vector`` or list of `float`
+        :param coordinates: defines coordinate system to be used
+        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param fixPotentialAtBottom: if true potential is fixed to zero at the
+                                     bottom of the domain in addition to the top
+        :type fixPotentialAtBottom: ``bool``
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        """
+        super(SelfDemagnetizationModel, self).__init__(domain, w, B, coordinates, fixPotentialAtBottom, tol)
+        #=========================================================
+        background_magnetic_flux_density = interpolate(background_magnetic_flux_density, B[0].getFunctionSpace())
+        if not self.getCoordinateTransformation().isCartesian():
+            s = self.getCoordinateTransformation().getScalingFactors()
+            v = self.getCoordinateTransformation().getVolumeFactor()
+            self.__B_r = background_magnetic_flux_density * s * v
+            self.__B_b = background_magnetic_flux_density / s
+
+            self.__fw = s**2 * v
+        else: # cartesian
+            self.__fw = 1
+            self.__B_r = background_magnetic_flux_density
+            self.__B_b = background_magnetic_flux_density
+
+        # keep track of k used to build PDE:
+        self.__last_k = None
+        # this is just the initial set_up
+        A=self.getPDE().createCoefficient("A")
+        for i in range(self.getDomain().getDim()):
+            A[i,i]=1.
+        self.getPDE().setValue(A=A)
+
+    def rescaleWeights(self, scale=1., k_scale=1.):
+        """
+        rescales the weights such that
+
+        *sum_s integrate( ( w_i[s] *B_i[s]) (w_j[s]*1/L_j) * L**2 * (background_magnetic_flux_density_j[s]*1/L_j) * k_scale )=scale*
+
+        :param scale: scale of data weighting factors
+        :type scale: positive ``float``
+        :param k_scale: scale of susceptibility.
+        :type k_scale: ``Scalar``
+        """
+        self._rescaleWeights(scale, inner(self.__B_r,1/self.edge_lengths ) * k_scale)
+
+    def getArguments(self, k):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :return: scalar magnetic potential and corresponding magnetic field
+        :rtype: ``Scalar``, ``Vector``
+        """
+        phi = self.getPotential(k)
+        grad_phi=grad(phi)
+        magnetic_flux_density = k * self.__B_b -(1+k)*grad_phi
+        return phi, grad_phi, magnetic_flux_density
+
+    def __updateA(self, k):
+        """
+        updates PDE coefficient if PDE is used with new k
+        """
+        pde=self.getPDE()
+        if self.__last_k is not k:
+           A=pde.getCoefficient('A')
+           if self.getCoordinateTransformation().isCartesian():
+               for i in range(self.getDomain().getDim()):
+                   A[i,i] = 1+k
+           else:
+               for i in range(self.getDomain().getDim()):
+                   A[i,i] = (1+k)*self.__fw[i]
+
+           self.__last_k = k
+           pde.setValue(A=A)
+
+    def getPotential(self, k):
+        """
+        Calculates the magnetic potential for a given susceptibility.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :return: magnetic potential
+        :rtype: ``Scalar``
+        """
+        self.__updateA(k)
+        pde=self.getPDE()
+        pde.resetRightHandSideCoefficients()
+        pde.setValue(X = k*self.__B_r)
+        phi=pde.getSolution()
+        return phi
+
+    def getDefect(self, k, phi, grad_phi, magnetic_flux_density):
+        """
+        Returns the value of the defect.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :param phi: corresponding potential
+        :type phi: ``Scalar``
+        :param magnetic_flux_density: magnetic field
+        :type magnetic_flux_density: ``Vector``
+        :rtype: ``float``
+        """
+        return self._getDefect(magnetic_flux_density)
+
+    def getGradient(self, k, phi, grad_phi, magnetic_flux_density):
+        """
+        Returns the gradient of the defect with respect to susceptibility.
+
+        :param k: susceptibility
+        :type k: ``Scalar``
+        :param phi: corresponding potential
+        :type phi: ``Scalar``
+        :param magnetic_flux_density: magnetic field
+        :type magnetic_flux_density: ``Vector``
+        :rtype: ``Scalar``
+        """
+        self.__updateA(k)
+        Y=self.getDefectGradient(magnetic_flux_density)
+        pde=self.getPDE()
+        pde.resetRightHandSideCoefficients()
+        pde.setValue(X=(1+k)*Y)
+        grad_YT=grad(pde.getSolution())
+
+        if self.getCoordinateTransformation().isCartesian(): # then b_r=B_b
+            return inner(grad_YT-Y, self.__B_r-grad_phi)
+        else:
+            return inner(grad_YT,self.__B_r-grad_phi)+inner(Y,grad_phi-self.__B_b)
+
diff --git a/downunder/py_src/forwardmodels/magnetotelluric2d.py b/downunder/py_src/forwardmodels/magnetotelluric2d.py
new file mode 100644
index 0000000..2594723
--- /dev/null
+++ b/downunder/py_src/forwardmodels/magnetotelluric2d.py
@@ -0,0 +1,554 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Forward models for 2D MT (TE and TM mode)"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['MT2DModelTEMode', 'MT2DModelTMMode']
+
+from .base import ForwardModel
+from esys.downunder.coordinates import makeTranformation
+from esys.escript import Data, Scalar, Vector, Function, FunctionOnBoundary, Solution
+from esys.escript.linearPDEs import LinearPDE, SolverOptions
+from esys.escript.util import *
+from math import pi as PI
+
+
+class MT2DBase(ForwardModel):
+    """
+    Base class for 2D MT forward models. See `MT2DModelTEMode` and
+    `MT2DModelTMMode` for actual implementations.
+    """
+    def __init__(self, domain, omega, x, Z, eta=None, w0=1., mu=4*PI*1e-7,
+                 Ftop=1., fixAtTop=False, fixAboveLevel=None, Fbottom=0.,
+                 fixAtBottom=False, coordinates=None, tol=1e-8,
+                 saveMemory=False, directSolver=True):
+        """
+        initializes a new forward model.
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param omega: frequency
+        :type omega: positive ``float``
+        :param x: coordinates of measurements
+        :type x: ``list`` of ``tuple`` with ``float``
+        :param Z: measured impedance (possibly scaled)
+        :type Z: ``list`` of ``complex``
+        :param eta: spatial confidence radius
+        :type eta:  positive ``float`` or ``list`` of  positive ``float``
+        :param w0: confidence factors for meassurements.
+        :type w0: ``None`` or a list of positive ``float``
+        :param mu: permeability
+        :type mu: ``float``
+        :param Ftop: value of field at top of the domain, see `fixAtTop` and
+                     `fixAboveLevel`
+        :type Ftop: ``float``, ``complex`` or ``Data`` of shape (2,)
+        :param fixAtTop: if true F is set to Ftop at the top of the domain.
+                         Use fixAtTop *or* fixAboveLevel, not both.
+        :type fixAtTop: ``bool``
+        :param fixAboveLevel: level above which F is set to Ftop (typically
+                              the level of the air layer).
+                              Use fixAtTop *or* fixAboveLevel, not both.
+        :type fixAboveLevel : ``float`` or ``None``
+        :param Fbottom: value of field at base of the domain
+        :type Fbottom: ``float``, ``complex`` or ``Data`` of shape (2,)
+        :param fixAtBottom: if true F is set to Fbottom at the bottom of the domain
+        :type fixAtBottom: ``bool``
+        :param coordinates: defines coordinate system to be used (not supported yet)
+        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        :param saveMemory: if true stiffness matrix is deleted after solution
+                           of the PDE to minimize memory use. This will
+                           require more compute time as the matrix needs to be
+                           reallocated at each iteration.
+        :type saveMemory: ``bool``
+        :param directSolver: if true a direct solver (rather than an iterative
+                             solver) will be used to solve the PDE
+        :type directSolver: ``bool``
+        """
+        super(MT2DBase, self).__init__()
+        self.__trafo = makeTranformation(domain, coordinates)
+        if not self.getCoordinateTransformation().isCartesian():
+            raise ValueError("Non-Cartesian coordinates are not supported yet.")
+        if len(x) != len(Z):
+            raise ValueError("Number of data points and number of impedance values don't match.")
+
+        if eta is None:
+            eta = sup(domain.getSize())*0.45
+
+        if isinstance(eta, float) or isinstance(eta, int):
+            eta = [float(eta)]*len(Z)
+        elif not len(eta) == len(Z):
+            raise ValueError("Number of confidence radii and number of impedance values don't match.")
+
+        if isinstance(w0, float) or isinstance(w0, int):
+            w0 =[float(w0)]*len(Z)
+        elif not len(w0) == len(Z):
+            raise ValueError("Number of confidence factors and number of impedance values don't match.")
+
+        self.__domain = domain
+        self._omega_mu = omega * mu
+
+        xx=Function(domain).getX()
+        totalS=0
+        self._Z = [ Scalar(0., Function(domain)),  Scalar(0., Function(domain)) ]
+        self._weight = Scalar(0., Function(domain))
+
+        for s in range(len(Z)):
+            chi = self.getWeightingFactor(xx, 1., x[s], eta[s])
+            f = integrate(chi)
+            if f < eta[s]**2 * 0.01 :
+                raise ValueError("Zero weight (almost) for data point %s. Change eta or refine mesh."%(s,))
+            w02 = w0[s]/f
+            totalS += w02
+            self._Z[0] += chi*Z[s].real
+            self._Z[1] += chi*Z[s].imag
+            self._weight += chi*w02/(abs(Z[s])**2)
+
+        if not totalS > 0:
+            raise ValueError("Scaling of weight factors failed as sum is zero.")
+
+        DIM = domain.getDim()
+        z = domain.getX()[DIM-1]
+        self._ztop = sup(z)
+        self._zbottom = inf(z)
+        self._q=Vector(0.,Solution(domain))
+        self._r=Vector(0.,Solution(domain))
+        #====================================
+        if fixAtTop or fixAboveLevel is not None:
+            if fixAtTop:
+                m=whereZero(z-self._ztop)
+            else:
+                m=whereNonNegative(z-fixAboveLevel)
+            if isinstance(Ftop, float) or isinstance(Ftop, int) :
+                d = Data((Ftop,0), Solution(domain))
+            elif isinstance(Ftop, tuple):
+                d = Data((Ftop[0],Ftop[1]), Solution(domain))
+            elif isinstance(Ftop, complex):
+                d = Data((Ftop.real,Ftop.imag), Solution(domain))
+            else:
+                if not Ftop.getShape() == (2,):
+                    raise ValueError("Expected shape of top value is (2,)")
+                d = Ftop
+            self._r+=m*d
+            self._q+=m*[1.,1.]
+        if fixAtBottom:
+            m=whereZero(z-self._zbottom)
+            if isinstance(Fbottom, float) or isinstance(Fbottom, int) :
+                d = Data((Fbottom,0), Solution(domain))
+            elif isinstance(Fbottom, tuple):
+                d = Data((Fbottom[0],Fbottom[1]), Solution(domain))
+            elif isinstance(Fbottom, complex):
+                d = Data((Fbottom.real,Fbottom.imag), Solution(domain))
+            else:
+                if not Fbottom.getShape() == (2,):
+                    raise ValueError("Expected shape of top value is (2,)")
+                d = Fbottom
+            self._r+=m*d
+            self._q+=m*[1.,1.]
+        #====================================
+        self.__tol = tol
+        self._directSolver = directSolver
+        self._saveMemory = saveMemory
+        self.__pde = None
+        if not saveMemory:
+            self.__pde = self.setUpPDE()
+
+    def getDomain(self):
+        """
+        Returns the domain of the forward model.
+
+        :rtype: `Domain`
+        """
+        return self.__domain
+
+    def getCoordinateTransformation(self):
+        """
+        returns the coordinate transformation being used
+
+        :rtype: ``CoordinateTransformation``
+        """
+        return self.__trafo
+
+    def setUpPDE(self):
+        """
+        Return the underlying PDE.
+
+        :rtype: `LinearPDE`
+        """
+        if self.__pde is None:
+            DIM=self.__domain.getDim()
+            pde=LinearPDE(self.__domain, numEquations=2)
+            if self._directSolver == True:
+                pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT)
+            D=pde.createCoefficient('D')
+            A=pde.createCoefficient('A')
+            pde.setValue(A=A, D=D, q=self._q)
+            pde.getSolverOptions().setTolerance(self.__tol)
+            pde.setSymmetryOff()
+        else:
+            pde=self.__pde
+            pde.resetRightHandSideCoefficients()
+        pde.setValue(X=pde.createCoefficient('X'), Y=pde.createCoefficient('Y'))
+        return pde
+
+    def getWeightingFactor(self, x, wx0, x0, eta):
+        """
+        returns the weighting factor
+        """
+        try:
+            origin, spacing, NE = x.getDomain().getGridParameters()
+            cell = [int((x0[i]-origin[i])/spacing[i]) for i in range(2)]
+            midpoint = [origin[i]+cell[i]*spacing[i]+spacing[i]/2. for i in range(2)]
+            return wx0 * whereNegative(length(x-midpoint)-eta)
+        except:
+            return wx0 * whereNegative(length(x-x0)-eta)
+
+    def getArguments(self, x):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+        Needs to be implemented in subclasses.
+        """
+        raise NotImplementedError
+
+    def getDefect(self, x, Ex, dExdz):
+        """
+        Returns the defect value. Needs to be implemented in subclasses.
+        """
+        raise NotImplementedError
+
+    def getGradient(self, x, Ex, dExdz):
+        """
+        Returns the gradient. Needs to be implemented in subclasses.
+        """
+        raise NotImplementedError
+
+
+class MT2DModelTEMode(MT2DBase):
+    """
+    Forward Model for two dimensional MT model in the TE mode for a given
+    frequency omega.
+    It defines a cost function:
+
+      *  defect = 1/2 integrate( sum_s w^s * ( E_x/H_y - Z_XY^s ) ) ** 2  *
+
+    where E_x is the horizontal electric field perpendicular to the YZ-domain,
+    horizontal magnetic field H_y=1/(i*omega*mu) * E_{x,z} with complex unit
+    i and permeability mu. The weighting factor w^s is set to 
+        *  w^s(X) = w_0^s  *
+    if length(X-X^s) <= eta and zero otherwise. X^s is the location of 
+    impedance measurement Z_XY^s, w_0^s is the level
+    of confidence (eg. 1/measurement error) and eta is level of spatial
+    confidence.
+
+    E_x is given as solution of the PDE
+
+        * -E_{x,ii} - i omega * mu * sigma * E_x = 0
+
+    where by default the normal derivative of E_x at the top of the domain 
+    is set to Ex_n=1 and E_x is set to zero at the bottom. Homogeneous Neuman
+    conditions are assumed elsewhere. If fixAtTop is set E_x is set to Ex_top. 
+    """
+    def __init__(self, domain, omega, x, Z_XY, eta=None, w0=1., mu=4*PI*1e-7,
+                 Ex_n=1, coordinates=None, Ex_top=1, fixAtTop=False, tol=1e-8,
+                 saveMemory=False, directSolver=True):
+        """
+        initializes a new forward model. See base class for a description of
+        the arguments.
+        """
+        
+        f = -1./(complex(0,1)*omega*mu)
+        scaledZXY = [ z*f for z in Z_XY ]
+        self.__Ex_n=complex(Ex_n)
+        super(MT2DModelTEMode, self).__init__(domain=domain, omega=omega, x=x, 
+                                              Z=scaledZXY, eta=eta, w0=w0, mu=mu, 
+                                              Ftop=Ex_top, fixAtTop=fixAtTop, fixAboveLevel= None, Fbottom=0., fixAtBottom=True, 
+                                              coordinates=coordinates, tol=tol, saveMemory=saveMemory, directSolver=directSolver)
+
+        
+    def getArguments(self, sigma):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param sigma: conductivity
+        :type sigma: ``Data`` of shape (2,)
+        :return: Ex_, Ex_,z
+        :rtype: ``Data`` of shape (2,)
+        """
+        DIM = self.getDomain().getDim()
+        pde = self.setUpPDE()
+        D = pde.getCoefficient('D')
+        f = self._omega_mu * sigma
+        D[0,1] = -f
+        D[1,0] =  f
+        A= pde.getCoefficient('A')
+        A[0,:,0,:]=kronecker(DIM)
+        A[1,:,1,:]=kronecker(DIM)
+        
+        Z = FunctionOnBoundary(self.getDomain()).getX()[DIM-1]
+        pde.setValue(A=A, D=D, y=whereZero(Z-self._ztop)*[self.__Ex_n.real,self.__Ex_n.imag],  r=self._r)
+        u = pde.getSolution()
+        return u, grad(u)[:,1]
+
+    def getDefect(self, sigma, Ex, dExdz):
+        """
+        Returns the defect value.
+
+        :param sigma: a suggestion for conductivity
+        :type sigma: ``Data`` of shape ()
+        :param Ex: electric field
+        :type Ex: ``Data`` of shape (2,)
+        :param dExdz: vertical derivative of electric field
+        :type dExdz: ``Data`` of shape (2,)
+
+        :rtype: ``float``
+        """
+        x=dExdz.getFunctionSpace().getX()
+        Ex=interpolate(Ex, x.getFunctionSpace())
+        u0=Ex[0]
+        u1=Ex[1]
+        u01=dExdz[0]
+        u11=dExdz[1]
+        scale = self._weight / ( u01**2 + u11**2 )
+
+        Z = self._Z
+        A = integrate(scale * ( (Z[0]**2+Z[1]**2)*(u01**2+u11**2)
+                              + 2*Z[1]*(u0*u11-u01*u1)
+                              - 2*Z[0]*(u0*u01+u11*u1)
+                              + u0**2 + u1**2 ))
+
+        return A/2
+
+    def getGradient(self, sigma, Ex, dExdz):
+        """
+        Returns the gradient of the defect with respect to density.
+
+        :param sigma: a suggestion for conductivity
+        :type sigma: ``Data`` of shape ()
+        :param Ex: electric field
+        :type Ex: ``Data`` of shape (2,)
+        :param dExdz: vertical derivative of electric field
+        :type dExdz: ``Data`` of shape (2,)
+        """
+        pde=self.setUpPDE()
+        DIM = self.getDomain().getDim()
+
+        x=dExdz.getFunctionSpace().getX()
+        Ex=interpolate(Ex, x.getFunctionSpace())
+        u0 = Ex[0]
+        u1 = Ex[1]
+        u01 = dExdz[0]
+        u11 = dExdz[1]
+
+        D=pde.getCoefficient('D')
+        Y=pde.getCoefficient('Y')
+        X=pde.getCoefficient('X')
+        A= pde.getCoefficient('A')
+
+        A[0,:,0,:]=kronecker(DIM)
+        A[1,:,1,:]=kronecker(DIM)
+        
+        f = self._omega_mu * sigma
+        D[0,1] =  f
+        D[1,0] = -f
+
+        Z = self._Z
+        scale = 1./( u01**2 + u11**2 )
+        scale2 = scale**2
+        scale *= self._weight
+        scale2 *= self._weight
+
+        Y[0] = scale * (u0 - u01*Z[0] + u11*Z[1])
+        Y[1] = scale * (u1 - u01*Z[1] - u11*Z[0])
+        X[0,1] = scale2 * (2*u01*u11*(Z[0]*u1-Z[1]*u0) \
+                + (Z[0]*u0+Z[1]*u1)*(u01**2-u11**2)
+                - u01*(u0**2 + u1**2))
+        X[1,1] = scale2 * (2*u01*u11*(Z[1]*u1+Z[0]*u0) \
+                + (Z[1]*u0-Z[0]*u1)*(u01**2-u11**2)
+                - u11*(u0**2 + u1**2))
+
+        pde.setValue(A=A, D=D, X=X, Y=Y)
+        Zstar=pde.getSolution()
+        return (-self._omega_mu)* (Zstar[1]*u0-Zstar[0]*u1)
+
+
+class MT2DModelTMMode(MT2DBase):
+    """
+    Forward Model for two-dimensional MT model in the TM mode for a given
+    frequency omega.
+    It defines a cost function:
+
+      *  defect = 1/2 integrate( sum_s w^s * ( rho*H_x/Hy - Z_YX^s ) ) ** 2  *
+
+    where H_x is the horizontal magnetic field perpendicular to the YZ-domain,
+    horizontal magnetic field H_y=1/(i*omega*mu) * E_{x,z} with complex unit
+    i and permeability mu. The weighting factor w^s is set to 
+        *  w^s(X) = w_0^s  *
+    if length(X-X^s) <= eta and zero otherwise. X^s is the location of 
+    impedance measurement Z_XY^s, w_0^s is the level
+    of confidence (eg. 1/measurement error) and eta is level of spatial
+    confidence.
+
+    H_x is given as solution of the PDE
+
+        * -(rho*H_{x,i})_{,i} + i omega * mu * H_x = 0
+
+    where H_x is set to Hx_top on the top of the domain. Homogeneous Neuman
+    conditions are assumed elsewhere. If fixAtBottom is set H_x is set to Hx_bottom
+    at the bottom of the domain overwrtining the Neuman condition. 
+    If fixAboveLevel is set then H_x is set to Hx_top for any location above and including fixAboveLevel
+    typically including teh top boundary. 
+    """
+    def __init__(self, domain, omega, x, Z_YX, eta=None, w0=1., mu=4*PI*1e-7,
+                 fixAboveLevel=None, Hx_top=1, coordinates=None, Hx_bottom=1.,
+                 fixAtBottom=False, tol=1e-8, saveMemory=False,
+                 directSolver=True):
+        """
+        initializes a new forward model. See base class for a description of
+        the arguments.
+        """
+        super(MT2DModelTMMode, self).__init__(domain=domain, omega=omega, x=x,
+                Z=Z_YX, eta=eta, w0=w0, mu=mu, Ftop=Hx_top, fixAtTop=True,
+                fixAboveLevel=fixAboveLevel, Fbottom=Hx_bottom,
+                fixAtBottom=fixAtBottom, coordinates=coordinates, tol=tol,
+                saveMemory=saveMemory, directSolver=directSolver)
+
+    def getArguments(self, rho):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param rho: resistivity
+        :type rho: ``Data`` of shape (2,)
+        :return: Hx, grad(Hx)
+        :rtype: ``tuple`` of ``Data``
+        """
+        DIM = self.getDomain().getDim()
+        pde = self.setUpPDE()
+        
+        D = pde.getCoefficient('D')
+        f = self._omega_mu
+        D[0,1] = -f
+        D[1,0] =  f
+        
+        A= pde.getCoefficient('A')
+        for i in xrange(DIM):
+            A[0,i,0,i]=rho
+            A[1,i,1,i]=rho
+        
+        pde.setValue(A=A, D=D, r=self._r)
+        u = pde.getSolution()
+        return u, grad(u)
+
+    def getDefect(self, rho, Hx, g_Hx):
+        """
+        Returns the defect value.
+
+        :param rho: a suggestion for resistivity
+        :type rho: ``Data`` of shape ()
+        :param Hx: magnetic field
+        :type Hx: ``Data`` of shape (2,)
+        :param g_Hx: gradient of magnetic field
+        :type g_Hx: ``Data`` of shape (2,2)
+
+        :rtype: ``float``
+        """
+        x = g_Hx.getFunctionSpace().getX()
+        Hx = interpolate(Hx, x.getFunctionSpace())
+        u0 = Hx[0]
+        u1 = Hx[1]
+        u01 = g_Hx[0,1]
+        u11 = g_Hx[1,1]
+        scale = rho / ( u0**2 + u1**2 )
+
+        Z = self._Z
+        A = integrate(self._weight * ( Z[0]**2 + Z[1]**2
+                                    + scale*(-2*Z[0]*(u0*u01 + u1*u11)
+                                             +2*Z[1]*(u1*u01 - u0*u11)
+                                             +rho*(u01**2 + u11**2)) ))
+        return A/2
+
+    def getGradient(self, rho, Hx, g_Hx):
+        """
+        Returns the gradient of the defect with respect to resistivity.
+
+        :param rho: a suggestion for resistivity
+        :type rho: ``Data`` of shape ()
+        :param Hx: magnetic field
+        :type Hx: ``Data`` of shape (2,)
+        :param g_Hx: gradient of magnetic field
+        :type g_Hx: ``Data`` of shape (2,2)
+        """
+        pde=self.setUpPDE()
+        DIM = self.getDomain().getDim()
+
+        x=g_Hx.getFunctionSpace().getX()
+        Hx=interpolate(Hx, x.getFunctionSpace())
+        u0 = Hx[0]
+        u1 = Hx[1]
+        u00 = g_Hx[0,0]
+        u10 = g_Hx[1,0]
+        u01 = g_Hx[0,1]
+        u11 = g_Hx[1,1]
+
+        A=pde.getCoefficient('A')
+        D=pde.getCoefficient('D')
+        Y=pde.getCoefficient('Y')
+        X=pde.getCoefficient('X')
+
+        for i in xrange(DIM):
+            A[0,i,0,i]=rho
+            A[1,i,1,i]=rho
+
+        f = self._omega_mu
+        D[0,1] =  f
+        D[1,0] = -f
+
+        Z = self._Z
+        scale = 1./( u0**2 + u1**2 )
+        scale2 = scale**2
+        scale *= self._weight
+        scale2 *= rho*self._weight
+        rho_scale = rho*scale
+
+        gscale = u01**2 + u11**2
+
+        Y[0] = scale2 * ( (Z[0]*u01+Z[1]*u11)*(u0**2-u1**2)
+                      + 2*u0*u1*(Z[0]*u11-Z[1]*u01)
+                      - rho*u0*gscale )
+        Y[1] = scale2 * ( (Z[0]*u11-Z[1]*u01)*(u1**2-u0**2)
+                      + 2*u0*u1*(Z[0]*u01+Z[1]*u11)
+                      - rho*u1*gscale )
+        X[0,1] = rho_scale * (-Z[0]*u0 + Z[1]*u1 + rho*u01)
+        X[1,1] = rho_scale * (-Z[0]*u1 - Z[1]*u0 + rho*u11)
+
+        pde.setValue(A=A, D=D, X=X, Y=Y)
+        g=grad(pde.getSolution())
+
+        Hstarr_x = g[0,0]
+        Hstari_x = g[1,0]
+        Hstarr_z = g[0,1]
+        Hstari_z = g[1,1]
+        return -scale*(u0*(Z[0]*u01+Z[1]*u11)+u1*(Z[0]*u11-Z[1]*u01)-rho*gscale)\
+               - Hstarr_x*u00 - Hstarr_z*u01 - Hstari_x*u10 - Hstari_z*u11
+
diff --git a/downunder/py_src/forwardmodels/pressure.py b/downunder/py_src/forwardmodels/pressure.py
new file mode 100644
index 0000000..72fe202
--- /dev/null
+++ b/downunder/py_src/forwardmodels/pressure.py
@@ -0,0 +1,102 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Isostatic Pressure calculation"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['IsostaticPressure']
+
+from esys.downunder.coordinates import makeTranformation
+from esys.escript import unitsSI as U
+from esys.escript import Scalar, Vector, Function
+from esys.escript.linearPDEs import LinearSinglePDE
+from esys.escript.util import *
+from math import pi as PI
+
+
+class IsostaticPressure(object):
+    """
+    class to calculate isostatic pressure field correction due to gravity forces
+    """
+    def __init__(self, domain, p0=0., level0=0, gravity0=-9.81*U.m*U.sec**(-3),
+                 background_density=2670* U.kg*U.m**(-3),
+                 gravity_constant=U.Gravitational_Constant,
+                 coordinates=None, tol=1e-8):
+        """
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param p0: pressure at level0
+        :type p0: scalar `Data` or ``float``
+        :param background_density: defines background_density in kg/m^3
+        :type background_density: ``float``
+        :param coordinates: defines coordinate system to be used
+        :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        :param level0: pressure for z>=`level0` is set to zero.
+        :type level0: ``float``
+        :param gravity0: vertical background gravity at `level0`
+        :type gravity0: ``float``
+        """
+        DIM=domain.getDim()
+        self.__domain = domain
+        self.__trafo=makeTranformation(domain, coordinates)
+        self.__pde=LinearSinglePDE(domain)
+        self.__pde.getSolverOptions().setTolerance(tol)
+        self.__pde.setSymmetryOn()
+
+        z = domain.getX()[DIM-1]
+        self.__pde.setValue(q=whereNonNegative(z-level0), r=p0)
+
+        fw = self.__trafo.getScalingFactors()**2 * self.__trafo.getVolumeFactor()
+        A=self.__pde.createCoefficient("A")
+        for i in range(DIM): A[i,i]=fw[i]
+        self.__pde.setValue(A=A)
+        z = Function(domain).getX()[DIM-1]
+        self.__g_b= 4*PI*gravity_constant/self.__trafo.getScalingFactors()[DIM-1]*background_density*(level0-z) + gravity0
+        self.__rho_b=background_density
+
+    def getPressure(self, g = None, rho=None):
+        """
+        return the pressure for gravity force anomaly `g` and
+        density anomaly `rho`
+
+        :param g: gravity anomaly data
+        :type g: ``Vector``
+        :param rho: gravity anomaly data
+        :type rho: ``Scalar``
+        :return: pressure distribution
+        :rtype: ``Scalar`
+        """
+        if not g: g=Vector(0., Function(self.__domain))
+        if not rho: rho=Scalar(0., Function(self.__domain))
+
+        g2=(rho * self.__g_b)*[0,0,1] + self.__rho_b*g + rho*g
+        # Tests need to be updated before the following is uncommented:
+        #g2=((rho+self.__rho_b) * self.__g_b)*[0,0,1] + self.__rho_b*g + rho*g
+        d=self.__trafo.getScalingFactors()
+        V= self.__trafo.getVolumeFactor()
+        self.__pde.setValue(X = -g2*d*V)
+        #self.__pde.setValue(X = g2*d*V)
+        return self.__pde.getSolution()
+
diff --git a/downunder/py_src/forwardmodels/subsidence.py b/downunder/py_src/forwardmodels/subsidence.py
new file mode 100644
index 0000000..e264e3a
--- /dev/null
+++ b/downunder/py_src/forwardmodels/subsidence.py
@@ -0,0 +1,135 @@
+from __future__ import print_function
+from __future__ import division
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+"""Forward model for Subsidence modelling"""
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+__all__ = ['Subsidence']
+
+from .base import ForwardModel
+from esys.escript import Data, FunctionOnBoundary
+from esys.escript.linearPDEs import LinearPDESystem
+from esys.escript.util import *
+
+
+class Subsidence(ForwardModel):
+    """
+    Forward Model for subsidence inversion minimizing
+    integrate( (inner(w,u)-d)**2)
+    where u is the surface displacement due to a pressure change P
+    """
+    def __init__(self, domain, w, d, lam, mu, coordinates=None, tol=1e-8):
+        """
+        Creates a new subsidence on the given domain
+
+        :param domain: domain of the model
+        :type domain: `Domain`
+        :param w: data weighting factors and direction
+        :type w: ``Vector`` with ``FunctionOnBoundary``
+        :param d: displacement measured at surface
+        :type d: ``Scalar`` with ``FunctionOnBoundary``
+        :param lam: 1st Lame coefficient
+        :type lam: ``Scalar`` with ``Function``
+        :param lam: 2st Lame coefficient/Shear modulus
+        :type lam: ``Scalar`` with ``Function``
+        :param coordinates: defines coordinate system to be used (not supported yet))
+        :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation`
+        :param tol: tolerance of underlying PDE
+        :type tol: positive ``float``
+        """
+        super(Subsidence, self).__init__()
+        DIM=domain.getDim()
+
+        self.__pde=LinearPDESystem(domain)
+        self.__pde.setSymmetryOn()
+        self.__pde.getSolverOptions().setTolerance(tol)
+        #... set coefficients ...
+        C=self.__pde.createCoefficient('A')
+        for i in range(DIM):
+            for j in range(DIM):
+                C[i,i,j,j]+=lam
+                C[i,j,i,j]+=mu
+                C[i,j,j,i]+=mu
+        x=domain.getX()
+        msk=whereZero(x[DIM-1])*kronecker(DIM)[DIM-1]
+        for i in range(DIM-1):
+            xi=x[i]
+            msk+=(whereZero(xi-inf(xi))+whereZero(xi-sup(xi))) *kronecker(DIM)[i]
+        self.__pde.setValue(A=C,q=msk)
+
+        self.__w=interpolate(w, FunctionOnBoundary(domain))
+        self.__d=interpolate(d, FunctionOnBoundary(domain))
+
+    def rescaleWeights(self, scale=1., P_scale=1.):
+        """
+        rescales the weights
+        
+        :param scale: scale of data weighting factors
+        :type scale: positive ``float``
+        :param P_scale: scale of pressure increment
+        :type P_scale: ``Scalar``
+        """
+        pass
+
+    def getArguments(self, P):
+        """
+        Returns precomputed values shared by `getDefect()` and `getGradient()`.
+
+        :param P: pressure
+        :type P: ``Scalar``
+        :return: displacement u
+        :rtype: ``Vector``
+        """
+        DIM=self.__pde.getDim()
+        self.__pde.setValue(y=Data(),X=P*kronecker(DIM))
+        u= self.__pde.getSolution()
+        return u,
+
+    def getDefect(self, P,u):
+        """
+        Returns the value of the defect.
+
+        :param P: pressure
+        :type P: ``Scalar``
+        :param u: corresponding displacement
+        :type u: ``Vector``
+        :rtype: ``float``
+        """
+        return 0.5*integrate((inner(u,self.__w)-self.__d)**2)
+
+    def getGradient(self, P, u):
+        """
+        Returns the gradient of the defect with respect to susceptibility.
+
+        :param P: pressure
+        :type P: ``Scalar``
+        :param u: corresponding displacement
+        :type u: ``Vector``
+        :rtype: ``Scalar``
+        """
+        d=inner(u,self.__w)-self.__d
+        self.__pde.setValue(y=d*self.__w,X=Data())
+        ustar=self.__pde.getSolution()
+
+        return div(ustar)
+
diff --git a/downunder/py_src/inversioncostfunctions.py b/downunder/py_src/inversioncostfunctions.py
index fb78fd6..94b169d 100644
--- a/downunder/py_src/inversioncostfunctions.py
+++ b/downunder/py_src/inversioncostfunctions.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Cost functions for inversions with one or more forward models"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -29,7 +29,7 @@ from .costfunctions import MeteredCostFunction
 from .mappings import Mapping
 from .forwardmodels import ForwardModel
 from esys.escript.pdetools import ArithmeticTuple
-from esys.escript import Data, inner
+from esys.escript import Data, inner, interpolate
 import numpy as np
 
 
@@ -136,7 +136,7 @@ class InversionCostFunction(MeteredCostFunction):
 
                 else:
                     if idx[0] != 0:
-                        raise ValueError("Level set index %s is out of range."%(k,))
+                        raise ValueError("Level set index %s is out of range."%(idx[0],))
                     else:
                         idx=None
             self.mappings.append((m,idx))
@@ -299,7 +299,10 @@ class InversionCostFunction(MeteredCostFunction):
                         else:
                             for k in range(idx): m[idx[k]]=m2[k]
                     else:
-                        m=m2
+                        if isinstance(m2, Data):
+                           m=interpolate(m2, m.getFunctionSpace())
+                        else:
+                           m=Data(m2, m.getFunctionSpace())
         return m
 
     def getProperties(self, m, return_list=False):
diff --git a/downunder/py_src/inversions.py b/downunder/py_src/inversions.py
index 9a76497..7ae990f 100644
--- a/downunder/py_src/inversions.py
+++ b/downunder/py_src/inversions.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Higher-level classes that allow running inversions with minimal set up"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/py_src/mappings.py b/downunder/py_src/mappings.py
index e0b23a0..4a996e9 100644
--- a/downunder/py_src/mappings.py
+++ b/downunder/py_src/mappings.py
@@ -1,7 +1,7 @@
-
+from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@
 """Collection of parametrizations that map physical values to model parameters
    and back"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -25,7 +25,8 @@ http://www.opensource.org/licenses/osl-3.0.php"""
 __url__="https://launchpad.net/escript-finley"
 
 __all__ = ['Mapping', 'DensityMapping', 'SusceptibilityMapping',\
-           'BoundedRangeMapping', 'LinearMapping', 'AcousticVelocityMapping']
+           'BoundedRangeMapping', 'LinearMapping', 'AcousticVelocityMapping',\
+           'MTMapping']
 
 from esys.escript import inf, sup, log, tanh, boundingBoxEdgeLengths, clip, atan2, sin, cos, sqrt, exp, whereZero
 import esys.escript.unitsSI as U
@@ -215,30 +216,42 @@ class AcousticVelocityMapping(Mapping):
 
 class DcResMapping(Mapping):
     """DcResMapping
-
-       sigma=sigma_reg * e^(k*m)     
+        sigmoid mapping
+        s=a/(1+e^(-k*m))    
     """
-    def __init__(self, sigma_prior, k=1.):
+    def __init__(self, sigma_prior, k=1., a=0.01, minVal=1/1000.):
         self.__sigma0=sigma_prior
         self.__k=k
-
+        self.a=a
+        self.minVal=minVal
     def getValue(self, m):
         print ("in get value inf(m)=",inf(m)," sup(m)=", sup(m))
-        return self.__sigma0 * (self.__k*m)
+        # s=self.__sigma0 + (self.__sigma0 * self.__k*m)
+        # s=self.__sigma0*exp(self.__k*m)
+        #### use sigmoid mapping
+        s=(self.__sigma0*self.a / (1+exp(-self.__k * m))) + self.minVal
+        print ("in get value inf(s)=",inf(s)," sup(s)=", sup(s))
+        if sup(s)!=0 and inf(s)!=0:
+            print ("in get value 1/inf(s)=",1./inf(s)," 1/sup(s)=", 1./sup(s))
+        return s
        
     def getDerivative(self, m):
         """
         returns the derivative of the mapping for m
         """
-        return self.__sigma0*self.__k*exp(self.__k*m)
+        # return self.__sigma0 * self.__k
+        # return self.__sigma0*self.__k*exp(self.__k*m)
+        return (self.__sigma0*self.__k*self.a*exp(-self.__k*m))/ (1+exp(-self.__k * m))**2
 
     def getInverse(self, s):
         """
         returns the value of the inverse of the mapping for s
         """
-        ms=whereZero(s)
-        ms0=whereZero(self.__sigma0)
-        m=1/self.__k* log(((1-ms)*s+ms*1)/((1-ms0)*self.__sigma0+ms0*1)) * (1-ms)*(1-ms0) 
+        # return (s-self.__sigma0) / (self.__sigma0 * self.__k)
+        if inf(((self.__sigma0*self.a)/s)) <= 1.:
+            raise ValueError("sigma 0*a/s < 1 this is not valid as log cannot be 0 or negative")
+        m= - 1./self.__k * log(((self.__sigma0*self.a)/(s-self.minVal))-1)
+        print ("inv(s)=",m)
         return m 
         
 
diff --git a/downunder/py_src/minimizers.py b/downunder/py_src/minimizers.py
index 965d212..385f181 100644
--- a/downunder/py_src/minimizers.py
+++ b/downunder/py_src/minimizers.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 """Generic minimization algorithms"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/py_src/regularizations.py b/downunder/py_src/regularizations.py
index 97c0c65..40b7293 100644
--- a/downunder/py_src/regularizations.py
+++ b/downunder/py_src/regularizations.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -240,7 +240,7 @@ class Regularization(CostFunction):
             self.__useDiagonalHessianApproximation=True
         self._update_Hessian=True
 
-        self.__num_tradeoff_factors=numLevelSets+((numLevelSets-1)*numLevelSets)/2
+        self.__num_tradeoff_factors=numLevelSets+((numLevelSets-1)*numLevelSets)//2
         self.setTradeOffFactors()
         self.__vol_d=vol(self.__domain)
 
diff --git a/downunder/py_src/seismic.py b/downunder/py_src/seismic.py
index 88fe240..d6977e5 100644
--- a/downunder/py_src/seismic.py
+++ b/downunder/py_src/seismic.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -96,15 +96,13 @@ class SimpleSEGYWriter(object):
         """
         A simple writer for 2D and 3D seismic lines, in particular for synthetic data
 
-        Typical usage:
+        Typical usage::
 
-           `from esys.escript import unitsSI as U`
-           `sw=SimpleSEGYWriter([0.,100*U.m,200*U,m,300.], source=200*U.m, sampling_interval=4*U.msec)`
-           `while n < 10:`
-
-           `   sw.addRecord([i*2., i*0.67, i**2, -i*7])`
-           
-           `sw.write('example.segy')`
+           from esys.escript import unitsSI as U
+           sw=SimpleSEGYWriter([0.,100*U.m,200*U,m,300.], source=200*U.m, sampling_interval=4*U.msec)
+           while n < 10:
+               sw.addRecord([i*2., i*0.67, i**2, -i*7])
+           sw.write('example.segy')
 
         :note: the writer uses `obspy`
         """
@@ -398,8 +396,8 @@ class VTIWave(WaveBase):
     """
     def __init__(self, domain, v_p, v_s, wavelet, source_tag,
             source_vector = [0.,0.,1.], eps=0., gamma=0., delta=0., rho=1.,
-            dt=None, u0=None, v0=None, absorption_zone=300*U.m,
-            absorption_cut=1e-2, lumping=True):
+            dt=None, u0=None, v0=None, absorption_zone=None,
+            absorption_cut=1e-2, lumping=True, disable_fast_assemblers=False):
         """
         initialize the VTI wave solver
 
@@ -424,6 +422,8 @@ class VTIWave(WaveBase):
         :param absorption_zone: thickness of absorption zone
         :param absorption_cut: boundary value of absorption decay factor
         :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion.
+        :param disable_fast_assemblers: if True, forces use of slower and more general PDE assemblers
+        :type disable_fast_assemblers: `boolean`
         """
         DIM=domain.getDim()
         f=createAbsorbtionLayerFunction(Function(domain).getX(), absorption_zone, absorption_cut)
@@ -450,7 +450,7 @@ class VTIWave(WaveBase):
 
         self.__wavelet=wavelet
 
-        self.fastAssembler = hasattr(domain, "setAssembler")
+        self.fastAssembler = hasattr(domain, "createAssembler") and not disable_fast_assemblers
         self.c33=v_p**2 * rho
         self.c44=v_s**2 * rho
         self.c11=(1+2*eps) * self.c33
@@ -478,6 +478,15 @@ class VTIWave(WaveBase):
         self.__r=Vector(0, DiracDeltaFunctions(self.__mypde.getDomain()))
         self.__r.setTaggedValue(self.__source_tag, source_vector)
 
+
+    def setQ(self,q):
+        """
+        sets the PDE q value
+
+        :param q: the value to set
+        """
+        self.__mypde.setValue(q=q)
+
     def _getAcceleration(self, t, u):
         """
         returns the acceleraton for time `t` and solution `u` at time `t`
@@ -531,8 +540,8 @@ class HTIWave(WaveBase):
         
         def __init__(self, domain, v_p, v_s,   wavelet, source_tag,
                 source_vector = [1.,0.,0.], eps=0., gamma=0., delta=0., rho=1.,
-                dt=None, u0=None, v0=None, absorption_zone=300*U.m,
-                absorption_cut=1e-2, lumping=True):
+                dt=None, u0=None, v0=None, absorption_zone=None,
+                absorption_cut=1e-2, lumping=True, disable_fast_assemblers=False):
            """
            initialize the VTI wave solver
 
@@ -557,6 +566,7 @@ class HTIWave(WaveBase):
            :param absorption_zone: thickness of absorption zone
            :param absorption_cut: boundary value of absorption decay factor
            :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion.
+           :param disable_fast_assemblers: if True, forces use of slower and more general PDE assemblers
            """
            DIM=domain.getDim()
            f=createAbsorbtionLayerFunction(Function(domain).getX(), absorption_zone, absorption_cut)
@@ -575,20 +585,20 @@ class HTIWave(WaveBase):
               v0=interpolate(v0, Solution(domain ))
 
            if dt == None:
-                  dt=min((1./5.)*min(inf(domain.getSize()/v_p), inf(domain.getSize()/v_s)), wavelet.getTimeScale())
+                dt=min((1./5.)*min(inf(domain.getSize()/v_p), inf(domain.getSize()/v_s)), wavelet.getTimeScale())
 
            super(HTIWave, self).__init__( dt, u0=u0, v0=v0, t0=0.)
 
            self.__wavelet=wavelet
            
-           self.fastAssembler = hasattr(domain, "setAssembler")
-           self.c33=v_p**2 * rho
-           self.c44=v_s**2 * rho
-           self.c11=(1+2*eps) * self.c33
-           self.c66=(1+2*gamma) * self.c44
-           self.c13=sqrt(2*self.c33*(self.c33-self.c44) * delta + (self.c33-self.c44)**2)-self.c44
-           self.c23=self.c33-2*self.c66
-           
+           self.fastAssembler = hasattr(domain, "createAssembler") and not disable_fast_assemblers
+           self.c33 = v_p**2 * rho
+           self.c44 = v_s**2 * rho
+           self.c11 = (1+2*eps) * self.c33
+           self.c66 = (1+2*gamma) * self.c44
+           self.c13 = sqrt(2*self.c33*(self.c33-self.c44) * delta + (self.c33-self.c44)**2)-self.c44
+           self.c23 = self.c33-2*self.c66
+
            if self.fastAssembler:
                 self.__mypde=WavePDE(domain, [("c11", self.c11),
                     ("c23", self.c23), ("c13", self.c13), ("c33", self.c33),
@@ -603,13 +613,20 @@ class HTIWave(WaveBase):
            self.__mypde.setValue(D=rho*kronecker(DIM))
            self.__source_tag=source_tag
 
-           if DIM ==2 :
+           if DIM == 2:
               source_vector= [source_vector[0],source_vector[2]]
 
            self.__r=Vector(0, DiracDeltaFunctions(self.__mypde.getDomain()))
            self.__r.setTaggedValue(self.__source_tag, source_vector)
 
 
+        def setQ(self,q):
+            """
+            sets the PDE q value
+
+            :param q: the value to set
+            """
+            self.__mypde.setValue(q=q)
 
         def  _getAcceleration(self, t, u):
              """
diff --git a/downunder/py_src/inversioncostfunctions.py b/downunder/py_src/splitinversioncostfunctions.py
similarity index 54%
copy from downunder/py_src/inversioncostfunctions.py
copy to downunder/py_src/splitinversioncostfunctions.py
index fb78fd6..ebf1ef2 100644
--- a/downunder/py_src/inversioncostfunctions.py
+++ b/downunder/py_src/splitinversioncostfunctions.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,24 +16,24 @@
 
 """Cost functions for inversions with one or more forward models"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
 http://www.opensource.org/licenses/osl-3.0.php"""
 __url__="https://launchpad.net/escript-finley"
 
-__all__ = [ 'InversionCostFunction']
+__all__ = [ 'SplitInversionCostFunction']
 
 from .costfunctions import MeteredCostFunction
 from .mappings import Mapping
 from .forwardmodels import ForwardModel
 from esys.escript.pdetools import ArithmeticTuple
-from esys.escript import Data, inner
+from esys.escript import Data, inner, addJobPerWorld, FunctionJob
 import numpy as np
 
 
-class InversionCostFunction(MeteredCostFunction):
+class SplitInversionCostFunction(MeteredCostFunction):
     """
     Class to define cost function *J(m)* for inversion with one or more
     forward models based on a multi-valued level set function *m*:
@@ -74,79 +74,44 @@ class InversionCostFunction(MeteredCostFunction):
     """
     provides_inverse_Hessian_approximation=True
 
-    def __init__(self, regularization, mappings, forward_models):
-        """
-        constructor for the cost function.
-        Stores the supplied object references and sets default weights.
-
-        :param regularization: the regularization part of the cost function
-        :type regularization: `Regularization`
-        :param mappings: the mappings to calculate physical parameters from the
-                         regularization. This is a list of 2-tuples *(map, i)*
-                         where the first component map defines a `Mapping` and
-                         the second component *i* defines the index of the
-                         component of level set function to be used to
-                         calculate the mapping. Items in the list may also be
-                         just `Mapping` objects in which case the entire level
-                         set function is fed into the `Mapping` (typically used
-                         for a single-component level set function.
-        :type mappings: `Mapping` or ``list``
-        :param forward_models: the forward models involved in the calculation
-                               of the cost function. This is a list of 2-tuples
-                               *(f, ii)* where the first component f defines a
-                               `ForwardModel` and the second component *ii* a
-                               list of indexes referring to the physical
-                               parameters in the `mappings` list. The 2-tuple
-                               can be replaced by a `ForwardModel` if the
-                               `mappings` list has a single entry.
-        :param forward_models: `ForwardModel` or ``list``
-        """
-        super(InversionCostFunction, self).__init__()
-        self.regularization=regularization
-        self.numLevelSets = self.regularization.getNumLevelSets()
-
-        if isinstance(mappings, Mapping):
-            mappings = [ mappings ]
-
-        self.mappings=[]
-        for i in range(len(mappings)):
-            mm=mappings[i]
-            if isinstance(mm, Mapping):
-                m=mm
-                if self.numLevelSets>1:
-                    idx=[ p for p in range(self.numLevelSets)]
-                else:
-                    idx=None
-            elif len(mm) == 1:
-                m=mm[0]
-                if self.numLevelSets>1:
-                    idx=[ p for p in range(self.numLevelSets)]
-                else:
-                    idx=None
-            else:
-                m=mm[0]
-                if isinstance(mm[1], int):
-                    idx=[mm[1]]
-                else:
-                    idx=list(mm[1])
-                if self.numLevelSets>1:
-                    for k in idx:
-                        if  k < 0  or k > self.numLevelSets-1:
-                            raise ValueError("level set index %s is out of range."%(k,))
-
-                else:
-                    if idx[0] != 0:
-                        raise ValueError("Level set index %s is out of range."%(k,))
-                    else:
-                        idx=None
-            self.mappings.append((m,idx))
-        self.numMappings=len(self.mappings)
-
-
+    # Original params for InversionCostFunction
+    # regularization --- need to feed in later
+    # mappings       --- could take a domain so need to be created later
+    # forward_models --- need to be split (do we have a function which takes a parameter to indicate which model to create?)
+    #
+    # New constructor
+    # num args, who many of each type
+    # splitw is the splitworld jobs are running on
+    # worldsinit_fn is run on each world at startup
+    def __init__(self, numLevelSets, numModels, numMappings, sw, worldsinit_fn):
+        """
+        fill this in.
+        """
+        super(SplitInversionCostFunction, self).__init__()
+        if numModels<1 or numModels<1 or numMappings<1:
+          raise ValueError("The inversion function requires at least one LevelSet, Mapping and Models.")
+        self.numModels=numModels
+        self.numMappings=numMappings
+        self.numLevelSets=numLevelSets
+        # sanity check
+        addJobPerWorld(sw, FunctionJob, worldsinit_fn)
+        sw.runJobs()
+        reqd=["models", "regularization", "mu_model","mappings"]
+        knownvars=sw.getVarList()
+        print(knownvars)
+        for n in reqd:
+          if [n,True] not in knownvars:
+            raise RuntimeError("Required variable "+n+" was not created by the world init function")
+        self.configured=False
+
+    # Function to put the (possible list of) forward model(s) into the form expected by the rest of the system
+    @staticmethod
+    def formatModels(forward_models, numMappings):
         if isinstance(forward_models, ForwardModel):
             forward_models = [ forward_models ]
-        self.forward_models=[]
+        result=[]
         for i in range(len(forward_models)):
+            print("Doing iteration "+str(i))
             f=forward_models[i]
             if isinstance(f, ForwardModel):
                 idx=[0]
@@ -160,27 +125,19 @@ class InversionCostFunction(MeteredCostFunction):
                 else:
                     idx=list(f[1])
                 for k in idx:
-                    if k<0 or k> self.numMappings:
+                    if k<0 or k> numMappings:
                         raise ValueError("mapping index %s in model %s is out of range."%(k,i))
                 fm=f[0]
-            self.forward_models.append((fm,idx))
-        self.numModels=len(self.forward_models)
-
-        trafo = self.regularization.getCoordinateTransformation()
-        for m in self.forward_models:
-            if not m[0].getCoordinateTransformation() == trafo:
-                raise ValueError("Coordinate transformation for regularization and model don't match.")
-
-        self.__num_tradeoff_factors = self.regularization.getNumTradeOffFactors() + self.numModels
-        self.setTradeOffFactorsModels()
-
+            result.append((fm,idx))
+        return result      
+      
     def getDomain(self):
         """
         returns the domain of the cost function
 
         :rtype: `Domain`
         """
-        self.regularization.getDomain()
+        raise RuntimeError("Can't extract domains for SplitInversionCostFunctions")
 
     def getNumTradeOffFactors(self):
         """
@@ -189,7 +146,10 @@ class InversionCostFunction(MeteredCostFunction):
 
         :rtype: ``int``
         """
-        return self.__num_tradeoff_factors
+        if self.configured:
+           return self.__num_tradeoff_factors
+        else:
+          raise RuntimeError("This inversion function has not been configured yet")
 
     def getForwardModel(self, idx=None):
         """
@@ -199,8 +159,7 @@ class InversionCostFunction(MeteredCostFunction):
                     can be omitted.
         :type idx: ``int``
         """
-        if idx==None: idx=0
-        return self.forward_models[idx][0]
+        raise RuntimeError("Can't extract forward models for SplitInversionCostFunctions")
 
     def getRegularization(self):
         """
@@ -208,7 +167,10 @@ class InversionCostFunction(MeteredCostFunction):
 
         :rtype: `Regularization`
         """
-        return self.regularization
+        if self.configured:
+           return self.regularization
+        else:
+          raise RuntimeError("This inversion function has not been configured yet")
 
     def setTradeOffFactorsModels(self, mu=None):
         """
@@ -233,13 +195,26 @@ class InversionCostFunction(MeteredCostFunction):
                     self.mu_model= [mu, ]
                 else:
                     raise ValueError("Trade-off factor must be positive.")
-
+        #Now we need to get these values into the subworlds
+        #Getting the mu value in via a closure is safe because it WILL NOT CONTAIN COMPLEX OBJECTS
+        extmu=self.mu_model
+        def setMu(self, **args):
+          chunksize=max(self.worldsize()//len(extmu),1)         #In case we have more worlds than models
+          minindex=self.subworldid()*chunksize
+          maxindex=(self.subworldid()+1)*chunksize              # yes this could go off the end but I will slice
+          mymu=extmu[minindex:maxindex]
+          self.exportValue("mu_model", mymu)
+        addJobPerWorld(sw, setMu)
+        sw.runJobs()
+        
     def getTradeOffFactorsModels(self):
         """
         returns the trade-off factors for the forward models
 
         :rtype: ``float`` or ``list`` of ``float``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")
         if self.numModels>1:
             return self.mu_model
         else:
@@ -275,6 +250,8 @@ class InversionCostFunction(MeteredCostFunction):
 
         :rtype: ``list`` of ``float``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")        
         mu1=self.getTradeOffFactorsModels(mu[:self.numModels])
         mu2=self.regularization.getTradeOffFactors()
         return [ m for m in mu1] + [ m for m in mu2]
@@ -287,6 +264,11 @@ class InversionCostFunction(MeteredCostFunction):
         `mappings` arguments in the constructor. Use ``None`` for properties
         for which no value is given.
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")        
+        #Since this involves solving a PDE (and therefore a domain, it must be kept local
+        #to each subworld
+        raise RuntimeError("This needs to run inside the subworld --- create a function for it")
         m=self.regularization.getPDE().createSolution()
         if len(props) > 0:
             for i in range(self.numMappings):
@@ -300,7 +282,7 @@ class InversionCostFunction(MeteredCostFunction):
                             for k in range(idx): m[idx[k]]=m2[k]
                     else:
                         m=m2
-        return m
+        #return m
 
     def getProperties(self, m, return_list=False):
         """
@@ -313,7 +295,11 @@ class InversionCostFunction(MeteredCostFunction):
         :type return_list: ``bool``
         :rtype: ``list`` of `Data`
         """
-
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")        
+        #Since this involves solving a PDE (and therefore a domain, it must be kept local
+        #to each subworld
+        raise RuntimeError("This needs to run inside the subworld --- create a function for it")        
         props=[]
         for i in range(self.numMappings):
             mp, idx=self.mappings[i]
@@ -327,10 +313,10 @@ class InversionCostFunction(MeteredCostFunction):
             else:
                 p=mp.getValue(m)
             props.append(p)
-        if self.numMappings > 1 or return_list:
-            return props
-        else:
-            return props[0]
+        #if self.numMappings > 1 or return_list:
+            #return props
+        #else:
+            #return props[0]
 
     def _getDualProduct(self, x, r):
         """
@@ -340,8 +326,40 @@ class InversionCostFunction(MeteredCostFunction):
         :type r: `ArithmeticTuple`
         :rtype: ``float``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")        
+        #This involves an 'x' which is a Data object.
+        #Does this only need to run on one subworld?
+        #Then shipped around using getDoubleValues?
+        raise RuntimeError("Still need to work this one out")        
         return self.regularization.getDualProduct(x, r)
 
+    
+    def setPoint(self):
+      self.setPoint()
+    
+    def _setPoint(self):
+      """
+      This should take in a value to set the point to, but that can wait
+      """
+      if not self.configured:
+        raise ValueError("This inversion function has not been configured yet")
+
+      def load_initial_guess(self, **args):
+          initguess=0
+          mods=self.importValue("models")
+          reg=self.importValue("regularization")
+          reg.setPoint(initguess)
+          for m,idx in mods:
+            pp=tuple( [props[k] for k in idx] ) # build up collection of properties used by this model
+            m.setPoint(*pp)
+          # We still need to deal with the props feild and where to get it from
+          self.exportValue("props", props)
+            
+      for i in range(0, self.sw.swcount):      
+          self.sw.addJob(FunctionJob, load_initial_guess, imports=["models", "regularization"])
+      self.sw.runJobs()
+      
     def _getArguments(self, m):
         """
         returns pre-computed values that are shared in the calculation of
@@ -356,6 +374,9 @@ class InversionCostFunction(MeteredCostFunction):
                  regularization
         :rtype: ``tuple``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")         
+        raise RuntimeError("Call to getArguments -- temporary block to see where this is used")
         args_reg=self.regularization.getArguments(m)
         # cache for physical parameters:
         props=self.getProperties(m, return_list=True)
@@ -368,6 +389,45 @@ class InversionCostFunction(MeteredCostFunction):
 
         return props, args_f, args_reg
 
+    def calculateValue(self, vnames):
+        self.calculate(vnames)
+        
+    def _calculateValue(self, vnames):
+        
+       if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")
+       #The props is already in each world as a variable
+       #Each model already has its point set
+       #regularization already has its point set
+        
+       def calculateValueWorker(self, vnames, **args):
+          props=self.importValue("props")
+          mods=self.importValue("models")
+          reg=self.importValue("regularization")
+          mu_model=self.importValue("mu_model")
+          
+          J=None
+          for i in range(len(mods)):    # note: iterating over local models not ones on other worlds
+            m,idx=mods[i]
+            z=m.getDefectAtPoint()
+            z*=self.mu_model[i];   
+            if J is None:          
+              J=z
+            else:
+              J+=z
+            
+          if self.worldid==0:    # we only want to add the regularization term once
+            J+=reg.getValueAtPoint()    # We actually want to get a value here but
+                                        # I want to distiguish it from the other getValue call
+          if isinstance(vnames, str):
+            self.exportValue(J, vnames)
+          else:
+            for n in vnames:
+              self.exportValue(J, n)
+       for i in range(0, self.sw.swcount):      
+          self.sw.addJob(FunctionJob, calculateValueWorker, imports=["models", "regularization", "props"])
+       self.sw.runJobs()              
+
     def _getValue(self, m, *args):
         """
         Returns the value *J(m)* of the cost function at *m*.
@@ -380,6 +440,9 @@ class InversionCostFunction(MeteredCostFunction):
                      regularization
         :rtype: ``float``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")         
+        raise RuntimeError("Call to getArguments -- temporary block to see where this is used")        
         if len(args)==0:
             args=self.getArguments(m)
 
@@ -400,6 +463,9 @@ class InversionCostFunction(MeteredCostFunction):
         return J
 
     def getComponentValues(self, m, *args):
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")       
+        raise RuntimeError("Call to getComponentValues -- temporary block to see where this is used")      
         return self._getComponentValues(m, *args)
 
     def _getComponentValues(self, m, *args):
@@ -411,6 +477,9 @@ class InversionCostFunction(MeteredCostFunction):
         :type x: x-type
         :rtype: ``list<<float>>``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")         
+        raise RuntimeError("Call to getArguments -- temporary block to see where this is used")        
         if len(args)==0:
             args=self.getArguments(m)
 
@@ -431,6 +500,117 @@ class InversionCostFunction(MeteredCostFunction):
 
         return result
 
+    def _calculateGradient(self):
+       if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")
+
+       numLevelSets=self.numLevelSets   # pass in via closure
+       def calculateGradientWorker(self, vnames1, vnames2, **args):
+          """
+          vnames1 gives the names to store the first component of the gradient in
+          vnames2 gives the names to store the second component of the gradient in
+          """
+          props=self.importValue("props")
+          mods=self.importValue("models")
+          reg=self.importValue("regularization")
+          mu_model=self.importValue("mu_model")
+          mappings=self.importValue("mappings")
+          
+          g_J = reg.getGradientAtPoint()
+          p_diffs=[]
+          # Find the derivative for each mapping
+          # If a mapping has a list of components (idx), then make a new Data object with only those
+          # components, pass it to the mapping and get the derivative.
+          for i in range(len(numMappings)):
+              mm, idx=mappings[i]
+              if idx and numLevelSets > 1:
+                  if len(idx)>1:
+                      m2=Data(0,(len(idx),),m.getFunctionSpace())
+                      for k in range(len(idx)): m2[k]=m[idx[k]]
+                      dpdm = mm.getDerivative(m2)
+                  else:
+                      dpdm = mm.getDerivative(m[idx[0]])
+              else:
+                  dpdm = mm.getDerivative(m)
+              p_diffs.append(dpdm)
+          #Since we are going to be merging Y with other worlds, we need to make sure the the regularization
+          #component is only added once.  However most of the ops below are in terms of += so we need to
+          #create a zero object to use as a starting point
+          if self.subworldid==0:
+             Y=g_J[0]    # Because g_J==(Y,X)  Y_k=dKer/dm_k
+          else:
+             Y=Data(0, g_J[0].getShape(), g_J[0].getForwardModel())
+          for i in range(self.numModels):
+              mu=self.mu_model[i]
+              f, idx_f=mods[i]
+              args=tuple( [ props[k] for k in idx_f]  + list( args_f[i] ) )
+              Ys = f.getGradientAtPoint() # this d Jf/d props
+              # in this case f depends on one parameter props only but this can
+              # still depend on several level set components
+              if Ys.getRank() == 0:
+                  # run through all level sets k prop j is depending on:
+                  idx_m=self.mappings[idx_f[0]][1]
+                  # tmp[k] = dJ_f/d_prop * d prop/d m[idx_m[k]]
+                  tmp=Ys * p_diffs[idx_f[0]] * mu
+                  if idx_m:
+                      if tmp.getRank()== 0:
+                          for k in range(len(idx_m)):
+                              Y[idx_m[k]]+=tmp # dJ_f /d m[idx_m[k]] = tmp
+                      else:
+                          for k in range(len(idx_m)):
+                              Y[idx_m[k]]+=tmp[k] # dJ_f /d m[idx_m[k]] = tmp[k]
+                  else:
+                      Y+=tmp # dJ_f /d m[idx_m[k]] = tmp
+              else:
+                  s=0
+                  # run through all props j forward model f is depending on:
+                  for j in range(len(idx_f)):
+                      # run through all level sets k prop j is depending on:
+                      idx_m=self.mappings[j][1]
+                      if p_diffs[idx_f[j]].getRank() == 0 :
+                          if idx_m: # this case is not needed (really?)
+                              raise RuntimeError("something wrong A")
+                              # tmp[k] = dJ_f/d_prop[j] * d prop[j]/d m[idx_m[k]]
+                              tmp=Ys[s]*p_diffs[idx_f[j]] * mu
+                              for k in range(len(idx_m)):
+                                  Y[idx_m[k]]+=tmp[k] # dJ_f /d m[idx_m[k]] = tmp[k]
+                          else:
+                              Y+=Ys[s]*p_diffs[idx_f[j]] * mu
+                          s+=1
+                      elif p_diffs[idx_f[j]].getRank() == 1 :
+                          l=p_diffs[idx_f[j]].getShape()[0]
+                          # tmp[k]=sum_j dJ_f/d_prop[j] * d prop[j]/d m[idx_m[k]]
+                          tmp=inner(Ys[s:s+l], p_diffs[idx_f[j]]) * mu
+                          if idx_m:
+                              for k in range(len(idx_m)):
+                                  Y[idx_m[k]]+=tmp # dJ_f /d m[idx_m[k]] = tmp[k]
+                          else:
+                              Y+=tmp
+                          s+=l
+                      else: # rank 2 case
+                          l=p_diffs[idx_f[j]].getShape()[0]
+                          Yss=Ys[s:s+l]
+                          if idx_m:
+                              for k in range(len(idx_m)):
+                                  # dJ_f /d m[idx_m[k]] = tmp[k]
+                                  Y[idx_m[k]]+=inner(Yss, p_diffs[idx_f[j]][:,k])
+                          else:
+                              Y+=inner(Yss, p_diffs[idx_f[j]]) * mu
+                          s+=l    
+          if isinstance(vnames1, str):
+            self.exportValue(Y, vnames1)
+          else:
+            for n in vnames1:
+              self.exportValue(Y, n)
+          if isinstance(vnames2, str):          #The second component should be strictly local 
+            self.exportValue(g_J[1], vnames2)
+          else:
+            for n in vnames2:
+              self.exportValue(g_J[1], n)
+              
+       addJobPerWorld(sw, FunctionJob, calculateGradientWorker, vnames, imports=["models", "regularization", "props", "mu_models"])
+       self.sw.runJobs()                 
+        
     def _getGradient(self, m, *args):
         """
         returns the gradient of the cost function at *m*.
@@ -448,6 +628,9 @@ class InversionCostFunction(MeteredCostFunction):
                gradients of fwd models. X is the gradient of the regularization
                w.r.t. gradient of m.
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")         
+        raise RuntimeError("Call to getGradient -- temporary block to see where this is used")        
         if len(args)==0:
             args = self.getArguments(m)
 
@@ -457,6 +640,9 @@ class InversionCostFunction(MeteredCostFunction):
 
         g_J = self.regularization.getGradient(m, *args_reg)
         p_diffs=[]
+        # Find the derivative for each mapping
+        # If a mapping has a list of components (idx), then make a new Data object with only those
+        # components, pass it to the mapping and get the derivative.
         for i in range(self.numMappings):
             mm, idx=self.mappings[i]
             if idx and self.numLevelSets > 1:
@@ -547,6 +733,10 @@ class InversionCostFunction(MeteredCostFunction):
         :note: in the current implementation only the regularization term is
                considered in the inverse Hessian approximation.
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")         
+        raise RuntimeError("Call to getInverseHessianApproximation -- temporary block to see where this is used")
+        
         m=self.regularization.getInverseHessianApproximation(m, r, *args[2])
         return m
 
@@ -554,6 +744,8 @@ class InversionCostFunction(MeteredCostFunction):
         """
         notifies the class that the Hessian operator needs to be updated.
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet")         
         self.regularization.updateHessian()
 
     def _getNorm(self, m):
@@ -564,5 +756,8 @@ class InversionCostFunction(MeteredCostFunction):
         :type m: `Data`
         :rtype: ``float``
         """
+        if not self.configured:
+          raise ValueError("This inversion function has not been configured yet") 
+        raise RuntimeError("Need to have this in a subworld --- one or all?")
         return self.regularization.getNorm(m)
 
diff --git a/downunder/py_src/splitminimizers.py b/downunder/py_src/splitminimizers.py
new file mode 100644
index 0000000..9757422
--- /dev/null
+++ b/downunder/py_src/splitminimizers.py
@@ -0,0 +1,231 @@
+##############################################################################
+#
+# Copyright (c) 2014-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+from .minimizers import AbstractMinimizer
+from esys.escriptcore.splitworld import Job
+
+
+class SplitMinimizerLBFGS(AbstractMinimizer):
+    """
+    Minimizer that uses the limited-memory Broyden-Fletcher-Goldfarb-Shanno
+    method.
+    
+    version modified to fit with split world.
+    """
+
+    # History size
+    _truncation = 30
+
+    # Initial Hessian multiplier
+    _initial_H = 1
+
+    # Restart after this many iteration steps
+    _restart = 60
+
+    def getOptions(self):
+        return {'truncation':self._truncation,'initialHessian':self._initial_H, 'restart':self._restart}
+
+    def setOptions(self, **opts):
+        self.logger.debug("Setting options: %s"%(str(opts)))
+        for o in opts:
+            if o=='historySize' or o=='truncation':
+                self._truncation=opts[o]
+            elif o=='initialHessian':
+                self._initial_H=opts[o]
+            elif o=='restart':
+                self._restart=opts[o]
+            else:
+                raise KeyError("Invalid option '%s'"%o)
+
+    def run(self):
+        """
+        This version relies on the costfunction already having an initial guess loaded.
+        It also does not return the result, meaning a job needs to be submitted to
+        get the result out.
+        """
+        if self.getCostFunction().provides_inverse_Hessian_approximation:
+            self.getCostFunction().updateHessian()
+            invH_scale = None
+        else:
+            invH_scale = self._initial_H
+
+        # start the iteration:
+        n_iter = 0
+        n_last_break_down=-1
+        non_curable_break_down = False
+        converged = False
+        
+
+	    
+	  
+        self.getCostFunction().setPoint()	# Set point to initial guess value (takes the place of a getArgs call)
+        #args=self.getCostFunction().getArguments(x)
+        
+        self.getCostFunction().calculateValue(["Jx","Jx_0"])	#evaluate the function and store the result in the named variables
+        self.getCostFunction().calculateGradient("g_Jx")        #compute the gradient and store the result
+        
+        #g_Jx=self.getCostFunction().getGradient(x, *args)
+        #Jx=self.getCostFunction()(x, *args) # equivalent to getValue() for Downunder CostFunctions
+        
+        
+        
+        Jx_0=Jx
+
+        while not converged and not non_curable_break_down and n_iter < self._imax:
+          k=0
+          break_down = False
+          s_and_y=[]
+          # initial step length for line search
+          alpha=1.0
+          self._doCallback(n_iter, x, Jx, g_Jx)
+
+          while not converged and not break_down and k < self._restart and n_iter < self._imax:
+                #self.logger.info("\033[1;31miteration %d\033[1;30m"%n_iter)
+                self.logger.info("********** iteration %3d **********"%n_iter)
+                self.logger.info("\tJ(x) = %s"%Jx)
+                #self.logger.debug("\tgrad f(x) = %s"%g_Jx)
+                if invH_scale:
+                    self.logger.debug("\tH = %s"%invH_scale)
+
+                # determine search direction
+                p = -self._twoLoop(invH_scale, g_Jx, s_and_y, x, *args)
+
+                # determine new step length using the last one as initial value
+                # however, avoid using too small steps for too long.
+                # FIXME: This is a bit specific to esys.downunder in that the
+                # inverse Hessian approximation is not scaled properly (only
+                # the regularization term is used at the moment)...
+                if invH_scale is None:
+                    if alpha <= 0.5:
+                        alpha=2*alpha
+                else:
+                    # reset alpha for the case that the cost function does not
+                    # provide an approximation of inverse H
+                    alpha=1.0
+                alpha, Jx_new, g_Jx_new = line_search(self.getCostFunction(), x, p, g_Jx, Jx, alpha)
+                # this function returns a scaling alpha for the search
+                # direction as well as the cost function evaluation and
+                # gradient for the new solution approximation x_new=x+alpha*p
+                self.logger.debug("\tSearch direction scaling alpha=%e"%alpha)
+
+                # execute the step
+                delta_x = alpha*p
+                x_new = x + delta_x
+
+                converged = True
+                if self._J_tol:
+                    flag=abs(Jx_new-Jx) <= self._J_tol * abs(Jx_new-Jx_0)
+                    if self.logger.isEnabledFor(logging.DEBUG):
+                        if flag:
+                            self.logger.debug("Cost function has converged: dJ, J*J_tol = %e, %e"%(Jx-Jx_new,abs(Jx_new-Jx_0)*self._J_tol))
+                        else:
+                            self.logger.debug("Cost function checked: dJ, J*J_tol = %e, %e"%(Jx-Jx_new,abs(Jx_new)*self._J_tol))
+
+                    converged = converged and flag
+                if self._m_tol:
+                    norm_x = self.getCostFunction().getNorm(x_new)
+                    norm_dx = self.getCostFunction().getNorm(delta_x)
+                    flag = norm_dx <= self._m_tol * norm_x
+                    if self.logger.isEnabledFor(logging.DEBUG):
+                        if flag:
+                            self.logger.debug("Solution has converged: dx, x*m_tol = %e, %e"%(norm_dx,norm_x*self._m_tol))
+                        else:
+                            self.logger.debug("Solution checked: dx, x*m_tol = %e, %e"%(norm_dx,norm_x*self._m_tol))
+                    converged = converged and flag
+
+                x=x_new
+                if converged:
+                    self.logger.info("\tJ(x) = %s"%Jx_new)
+                    break
+
+                # unfortunately there is more work to do!
+                if g_Jx_new is None:
+                    args=self.getCostFunction().getArguments(x_new)
+                    g_Jx_new=self.getCostFunction().getGradient(x_new, args)
+                delta_g=g_Jx_new-g_Jx
+
+                rho=self.getCostFunction().getDualProduct(delta_x, delta_g)
+                if abs(rho)>0:
+                    s_and_y.append((delta_x,delta_g, rho ))
+                else:
+                    break_down=True
+
+                self.getCostFunction().updateHessian()
+                g_Jx=g_Jx_new
+                Jx=Jx_new
+
+                k+=1
+                n_iter+=1
+                self._doCallback(n_iter, x, Jx, g_Jx)
+
+                # delete oldest vector pair
+                if k>self._truncation: s_and_y.pop(0)
+
+                if not self.getCostFunction().provides_inverse_Hessian_approximation and not break_down:
+                    # set the new scaling factor (approximation of inverse Hessian)
+                    denom=self.getCostFunction().getDualProduct(delta_g, delta_g)
+                    if denom > 0:
+                        invH_scale=self.getCostFunction().getDualProduct(delta_x,delta_g)/denom
+                    else:
+                        invH_scale=self._initial_H
+                        self.logger.debug("** Break down in H update. Resetting to initial value %s."%self._initial_H)
+          # case handling for inner iteration:
+          if break_down:
+              if n_iter == n_last_break_down+1:
+                  non_curable_break_down = True
+                  self.logger.debug("** Incurable break down detected in step %d."%n_iter)
+              else:
+                  n_last_break_down = n_iter
+                  self.logger.debug("** Break down detected in step %d. Iteration is restarted."%n_iter)
+          if not k < self._restart:
+              self.logger.debug("Iteration is restarted after %d steps."%n_iter)
+
+        # case handling for inner iteration:
+        self._result=x
+        if n_iter >= self._imax:
+            self.logger.warn(">>>>>>>>>> Maximum number of iterations reached! <<<<<<<<<<")
+            raise MinimizerMaxIterReached("Gave up after %d steps."%n_iter)
+        elif non_curable_break_down:
+            self.logger.warn(">>>>>>>>>> Incurable breakdown! <<<<<<<<<<")
+            raise MinimizerIterationIncurableBreakDown("Gave up after %d steps."%n_iter)
+
+        self.logger.info("Success after %d iterations!"%n_iter)
+        #This version does nor return the result
+        #You need to set up a job to extract the result
+
+    def _twoLoop(self, invH_scale, g_Jx, s_and_y, x, *args):
+        """
+        Helper for the L-BFGS method.
+        See 'Numerical Optimization' by J. Nocedal for an explanation.
+        """
+        q=g_Jx
+        alpha=[]
+        for s,y, rho in reversed(s_and_y):
+            a=self.getCostFunction().getDualProduct(s, q)/rho
+            alpha.append(a)
+            q=q-a*y
+
+        if self.getCostFunction().provides_inverse_Hessian_approximation:
+             r = self.getCostFunction().getInverseHessianApproximation(x, q, *args)
+        else:
+             r = invH_scale * q
+
+        for s,y,rho in s_and_y:
+            beta = self.getCostFunction().getDualProduct(r, y)/rho
+            a = alpha.pop()
+            r = r + s * (a-beta)
+        return r
+        
+    
\ No newline at end of file
diff --git a/downunder/py_src/regularizations.py b/downunder/py_src/splitregularizations.py
similarity index 97%
copy from downunder/py_src/regularizations.py
copy to downunder/py_src/splitregularizations.py
index 97c0c65..01e38bb 100644
--- a/downunder/py_src/regularizations.py
+++ b/downunder/py_src/splitregularizations.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,14 +14,14 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
 http://www.opensource.org/licenses/osl-3.0.php"""
 __url__="https://launchpad.net/escript-finley"
 
-__all__ = ['Regularization']
+__all__ = ['SplitRegularization']
 
 
 import logging
@@ -32,7 +32,7 @@ from esys.escript.pdetools import ArithmeticTuple
 from .coordinates import makeTranformation
 from .costfunctions import CostFunction
 
-class Regularization(CostFunction):
+class SplitRegularization(CostFunction):
     """
     The regularization term for the level set function ``m`` within the cost
     function J for an inversion:
@@ -105,6 +105,8 @@ class Regularization(CostFunction):
         if wc is None and numLevelSets>1:
             raise ValueError("Values for wc must be given.")
 
+        self.__pre_input = None
+        self.__pre_args = None
         self.logger = logging.getLogger('inv.%s'%self.__class__.__name__)
         self.__domain=domain
         DIM=self.__domain.getDim()
@@ -240,7 +242,7 @@ class Regularization(CostFunction):
             self.__useDiagonalHessianApproximation=True
         self._update_Hessian=True
 
-        self.__num_tradeoff_factors=numLevelSets+((numLevelSets-1)*numLevelSets)/2
+        self.__num_tradeoff_factors=numLevelSets+((numLevelSets-1)*numLevelSets)//2
         self.setTradeOffFactors()
         self.__vol_d=vol(self.__domain)
 
@@ -401,6 +403,8 @@ class Regularization(CostFunction):
     def getArguments(self, m):
         """
         """
+        self.__pre_args = grad(m)
+        self.__pre_input = m
         return grad(m),
 
     def getValue(self, m, grad_m):
@@ -410,6 +414,12 @@ class Regularization(CostFunction):
 
         :rtype: ``float``
         """
+        
+        # substituting cached values
+        m=self.__pre_input
+        grad_m=self.__pre_args
+        
+        
         mu=self.__mu
         mu_c=self.__mu_c
         DIM=self.getDomain().getDim()
@@ -450,6 +460,10 @@ class Regularization(CostFunction):
         :note: This implementation returns Y_k=dPsi/dm_k and X_kj=dPsi/dm_kj
         """
 
+        # substituting cached values
+        m=self.__pre_input
+        grad_m=self.__pre_args        
+        
         mu=self.__mu
         mu_c=self.__mu_c
         DIM=self.getDomain().getDim()
@@ -493,6 +507,11 @@ class Regularization(CostFunction):
     def getInverseHessianApproximation(self, m, r, grad_m, solve=True):
         """
         """
+
+        # substituting cached values
+        m=self.__pre_input
+        grad_m=self.__pre_args
+
         if self._new_mu or self._update_Hessian:
             self._new_mu=False
             self._update_Hessian=False
diff --git a/downunder/test/python/SConscript b/downunder/test/python/SConscript
index 8591403..366e0b8 100644
--- a/downunder/test/python/SConscript
+++ b/downunder/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/downunder/test/python/inversion_acoustictest_2d.py b/downunder/test/python/inversion_acoustictest_2d.py
index d5a76a1..0a0794c 100644
--- a/downunder/test/python/inversion_acoustictest_2d.py
+++ b/downunder/test/python/inversion_acoustictest_2d.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -20,7 +20,7 @@
 
 """
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_coordinates.py b/downunder/test/python/run_coordinates.py
index e1f7f27..e30c401 100644
--- a/downunder/test/python/run_coordinates.py
+++ b/downunder/test/python/run_coordinates.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_datasources.py b/downunder/test/python/run_datasources.py
index 1d7370d..e209b32 100644
--- a/downunder/test/python/run_datasources.py
+++ b/downunder/test/python/run_datasources.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -127,7 +127,7 @@ class TestNumpyData(unittest.TestCase):
 
         out=np.genfromtxt(outfn, delimiter=',', skip_header=1, dtype=np.float64)
         # recompute nz since ripley might have adjusted number of elements
-        nz=len(out)/nx
+        nz=len(out)//nx
         g_out=out[:,0].reshape(nz,nx)
         s_out=out[:,1].reshape(nz,nx)
         self.assertAlmostEqual(np.abs(
@@ -176,7 +176,7 @@ class TestNumpyData(unittest.TestCase):
 
         out=np.genfromtxt(outfn, delimiter=',', skip_header=1, dtype=np.float64)
         # recompute nz since ripley might have adjusted number of elements
-        nz=len(out)/(nx*ny)
+        nz=len(out)//(nx*ny)
         g_out=out[:,0].reshape(nz,ny,nx)
         s_out=out[:,1].reshape(nz,ny,nx)
         self.assertAlmostEqual(np.abs(
@@ -242,7 +242,7 @@ class TestErMapperData(unittest.TestCase):
 
         out=np.genfromtxt(outfn, delimiter=',', skip_header=1, dtype=np.float64)
         # recompute nz since ripley might have adjusted number of elements
-        nz=len(out)/(nx*ny)
+        nz=len(out)//(nx*ny)
         g_out=out[:,0].reshape(nz,ny,nx)
         s_out=out[:,1].reshape(nz,ny,nx)
         self.assertAlmostEqual(np.abs(
@@ -303,7 +303,7 @@ class TestNetCdfData(unittest.TestCase):
         out=np.genfromtxt(outfn, delimiter=',', skip_header=1, dtype=np.float64)
         # recompute nz since ripley might have adjusted number of elements
 
-        nz=len(out)/(nx*ny)
+        nz=len(out)//(nx*ny)
         g_out=out[:,0].reshape(nz,ny,nx)
         s_out=out[:,1].reshape(nz,ny,nx)
 
@@ -359,7 +359,7 @@ class TestNetCdfData(unittest.TestCase):
         out=np.genfromtxt(outfn, delimiter=',', skip_header=1, dtype=np.float64)
         
         # recompute nz since ripley might have adjusted number of elements
-        nz=len(out)/(nx*ny)
+        nz=len(out)//(nx*ny)
         g_out=out[:,0].reshape(nz,ny,nx)
         s_out=out[:,1].reshape(nz,ny,nx)
 
diff --git a/downunder/test/python/run_dcforward.py b/downunder/test/python/run_dcforward.py
index 99e250b..e65cae4 100644
--- a/downunder/test/python/run_dcforward.py
+++ b/downunder/test/python/run_dcforward.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -67,17 +67,17 @@ class TestDCResistivityForward(unittest.TestCase):
         else:
             if not HAVE_GMSH:
                 raise unittest.SkipTest("gmsh required for test")
-            lc=50.0
+            lc=30.0
             bufferThickness=3000
             extents=[1000,2000,2000]
-            electrodeDict={}
+            electrodeLst=[]
             lcDiv=10
-            electrodeDict["e1"]=[0.2*extents[0], 0.5*extents[1], 0,lc/lcDiv]
-            electrodeDict["e2"]=[0.4*extents[0], 0.5*extents[1], 0,lc/lcDiv]
-            electrodeDict["e3"]=[0.6*extents[0], 0.5*extents[1], 0,lc/lcDiv]
-            electrodeDict["e4"]=[0.8*extents[0], 0.5*extents[1], 0,lc/lcDiv]
+            electrodeLst.append(("e1",[-0.4*extents[0], 0, 0,lc/lcDiv]))
+            electrodeLst.append(("e2",[-0.2*extents[0], 0, 0,lc/lcDiv]))
+            electrodeLst.append(("e3",[0.2*extents[0], 0, 0,lc/lcDiv]))
+            electrodeLst.append(("e4",[0.4*extents[0], 0, 0,lc/lcDiv]))
             runName=os.path.join(WORKDIR, "dcResPolePole%d-%d"%(lc,lc/lcDiv))
-            domGen=DCResDomGenerator(extents, electrodeDict,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
+            domGen=DCResDomGenerator(extents, electrodeLst,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
             dom = domGen.getDom(mshName=runName+".msh")
             if mpirank==0: 
                 os.unlink(runName+".msh")
@@ -86,7 +86,7 @@ class TestDCResistivityForward(unittest.TestCase):
         secondaryConductivity=Scalar(1/130., ContinuousFunction(dom))
         current=1000.
         a=4*0.05*extents[0]
-        midPoint = [0.5*extents[0],0.5*extents[1]]
+        midPoint = [0,0]
         directionVector=[1.,0.]
         numElectrodes = 4
 
@@ -95,49 +95,57 @@ class TestDCResistivityForward(unittest.TestCase):
         totalApparentResList = pps.getApparentResistivityTotal()
         for i in totalApparentResList:
             res_a = abs(i-totalApparentRes)
-            res_b = 0.05 * totalApparentRes
+            res_b = 0.075 * totalApparentRes
             self.assertLess(res_a, res_b, "result of %g greater than tolerance of %g"%(res_a, res_b))
 
     def test_getPotential3dSchlumberger(self):
-        structured=True
-        totalApparentRes = 130.
+        structured=False
+        numElectrodes = 12
+        directionVector=[1.,0.]
+        midPoint=[]
+        totalApparentResVal = 130.
+        current=0.5
+        interval_a = 5
+        interval_n = 5
+
+
         if structured:
-            extents=[100,100,100]
-            dom=Brick(25,25,25,l0=extents[0],l1=extents[1],l2=-extents[2])
+            #does not work because finley does not allow the specification of domain origin
+            extents=[200,200,200]
+            dom=Brick(25,25,25,l0=(-extents[0]/2,extents[0]/2),l1=(-extents[1]/2,extents[1]/2),l2=-extents[2])
+            midPoint = [0,0]
         else:
             if not HAVE_GMSH:
                 raise unittest.SkipTest("gmsh required for test")
-            lc=50.0
-            bufferThickness=3000
-            extents=[1000,2000,2000]
-            electrodeDict={}
-            lcDiv=10
-            electrodeDict["e1"]=[440., 0.5*extents[1], 0,lc/lcDiv]
-            electrodeDict["e2"]=[480., 0.5*extents[1], 0,lc/lcDiv]
-            electrodeDict["e3"]=[520., 0.5*extents[1], 0,lc/lcDiv]
-            electrodeDict["e4"]=[560., 0.5*extents[1], 0,lc/lcDiv]
+            lc=10.0
+            bufferThickness=100
+            extents=[200,200,200]
+            midPoint = [0,0]
+            lcDiv=10.0
+            electrodes=[]
+            start=[]
+            start.append(midPoint[0] - (((numElectrodes-1)*interval_a)/2. * directionVector[0]))
+            start.append(midPoint[1] - (((numElectrodes-1)*interval_a)/2. * directionVector[1]))
+            electrodeTags=[]
+            electrodeLst=[]
+            for i in range(numElectrodes):
+                electrodes.append([start[0]+(directionVector[0]*i*interval_a), start[1]+(directionVector[1]*i*interval_a),0])
+                electrodeTags.append("e%d"%i)
+                electrodeLst.append([electrodeTags[i]],[electrodes[i][0], electrodes[i][1], electrodes[i][2], lc/lcDiv])
             runName=os.path.join(WORKDIR, "dcResSchlum%d-%d"%(lc,lc/lcDiv))
-            domGen=DCResDomGenerator(extents, electrodeDict,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
-            dom = domGen.getDom(mshName=runName+".msh")
+            domGen=DCResDomGenerator(extents, electrodeLst,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
+            dom = domGen.getDom(mshName=runName+".msh",fieldSize=[70,100])
+            fn = domGen.getFileName()
             if mpirank==0: 
                 os.unlink(runName+".msh")
-        totalApparentResVal = 130.
+            
         primaryConductivity=Scalar(1/100., ContinuousFunction(dom))
-        secondaryConductivity=Scalar(1/130., ContinuousFunction(dom))
-        current=1000.
-        numElectrodes = 12
-        interval_a = 4
-        midPoint = [0.5*extents[0]+interval_a/2,0.5*extents[1]]
-        directionVector=[1.,0.]
-        interval_n = 5
-        
+        secondaryConductivity=Scalar(1/130., ContinuousFunction(dom))    
         schs=SchlumbergerSurvey(dom, primaryConductivity, secondaryConductivity,
                 current, interval_a, interval_n, midPoint, directionVector,
                 numElectrodes)
-        schs.getPotential()
-        primaryApparentRes=schs.getApparentResistivityPrimary()
-        SecondaryApparentRes=schs.getApparentResistivitySecondary()
-        totalApparentRes=schs.getApparentResistivityTotal()
+        potentials=schs.getPotentialAnalytic()
+        totalApparentRes=schs.getApparentResistivity(potentials[2])
         for i in totalApparentRes:
             for j in i:
                 res_a = abs(j-totalApparentResVal)
@@ -156,23 +164,23 @@ class TestDCResistivityForward(unittest.TestCase):
             lc=10.0
             bufferThickness=300
             extents=[100,100,100]
-            electrodeDict={}
+            electrodeLst=[]
             lcDiv=10
-            electrodeDict["e0" ] = [28.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e1" ] = [32.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e2" ] = [36.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e3" ] = [40.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e4" ] = [44.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e5" ] = [48.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e6" ] = [52.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e7" ] = [56.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e8" ] = [60.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e9" ] = [64.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e10"] = [68.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e11"] = [72.0, 48.0, 0, lc/lcDiv]
+            electrodeLst.append(("e0" , [-22.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e1" , [-18.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e2" , [-14.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e3" , [-10.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e4" , [-6.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e5" , [-2.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e6" , [ 2.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e7" , [ 6.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e8" , [ 10.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e9" , [ 14.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e10", [ 18.0, 0.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e11", [ 22.0, 0.0, 0, lc/lcDiv]))
             runName=os.path.join(WORKDIR, "dcResdipdip%d-%d"%(lc,lc/lcDiv))
-            domGen=DCResDomGenerator(extents, electrodeDict,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
-            dom = domGen.getDom(mshName=runName+".msh")
+            domGen=DCResDomGenerator(extents, electrodeLst,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
+            dom = domGen.getDom(mshName=runName+".msh",reUse=False)
             if mpirank==0: 
                 os.unlink(runName+".msh")
         n=5
@@ -183,7 +191,7 @@ class TestDCResistivityForward(unittest.TestCase):
         numElectrodes = 12
         # a=(.8*extents[0])/numElectrodes
         a=4
-        midPoint = [0.5*extents[0],0.5*extents[1] - 2]
+        midPoint = [0,0]
         directionVector=[1.,0.]
         dipdips=DipoleDipoleSurvey(dom, primaryConductivity, secondaryConductivity, current, a,n, midPoint, directionVector, numElectrodes)
         dipdips.getPotential()
@@ -208,23 +216,23 @@ class TestDCResistivityForward(unittest.TestCase):
             lc=50.0
             bufferThickness=3000
             extents=[1000,2000,2000]
-            electrodeDict={}
+            electrodeLst=[]
             lcDiv=10
 
-            electrodeDict["e0" ] = [28.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e1" ] = [32.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e2" ] = [36.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e3" ] = [40.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e4" ] = [44.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e5" ] = [48.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e6" ] = [52.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e7" ] = [56.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e8" ] = [60.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e9" ] = [64.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e10"] = [68.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e11"] = [72.0, 48.0, 0, lc/lcDiv]
+            electrodeLst.append(("e0"  , [28.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e1"  , [32.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e2"  , [36.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e3"  , [40.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e4"  , [44.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e5"  , [48.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e6"  , [52.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e7"  , [56.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e8"  , [60.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e9"  , [64.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e10" , [68.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e11" , [72.0, 48.0, 0, lc/lcDiv]))
 
-            domGen=DCResDomGenerator(extents, electrodeDict,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
+            domGen=DCResDomGenerator(extents, electrodeLst,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
             runName=os.path.join(WORKDIR, "wenner%d-%d"%(lc,lc/lcDiv))
             dom = domGen.getDom(mshName=runName+".msh")
             if mpirank==0: 
@@ -261,22 +269,22 @@ class TestDCResistivityForward(unittest.TestCase):
             lc=10.0
             bufferThickness=300
             extents=[100,100,100]
-            electrodeDict={}
+            electrodeLst=[]
             lcDiv=10
-            electrodeDict["e0" ] = [28.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e1" ] = [32.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e2" ] = [36.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e3" ] = [40.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e4" ] = [44.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e5" ] = [48.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e6" ] = [52.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e7" ] = [56.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e8" ] = [60.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e9" ] = [64.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e10"] = [68.0, 48.0, 0, lc/lcDiv]
-            electrodeDict["e11"] = [72.0, 48.0, 0, lc/lcDiv]
+            electrodeLst.append(("e0"  , [28.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e1"  , [32.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e2"  , [36.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e3"  , [40.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e4"  , [44.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e5"  , [48.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e6"  , [52.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e7"  , [56.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e8"  , [60.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e9"  , [64.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e10" , [68.0, 48.0, 0, lc/lcDiv]))
+            electrodeLst.append(("e11" , [72.0, 48.0, 0, lc/lcDiv]))
             runName=os.path.join(WORKDIR, "dcRespoldip%d-%d"%(lc,lc/lcDiv))
-            domGen=DCResDomGenerator(extents, electrodeDict,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
+            domGen=DCResDomGenerator(extents, electrodeLst,lc=lc,tmpDir=WORKDIR,bufferThickness=bufferThickness,prism=None)
             dom = domGen.getDom(mshName=runName+".msh")
             if mpirank==0: 
                 os.unlink(runName+".msh")
diff --git a/downunder/test/python/run_domainbuilder.py b/downunder/test/python/run_domainbuilder.py
index f45e90f..0d69068 100644
--- a/downunder/test/python/run_domainbuilder.py
+++ b/downunder/test/python/run_domainbuilder.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_forward.py b/downunder/test/python/run_forward.py
index 6b69ec2..b1a1ee3 100644
--- a/downunder/test/python/run_forward.py
+++ b/downunder/test/python/run_forward.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -62,8 +62,8 @@ try:
 except KeyError:
     WORKDIR='.'
 
-    
-have_direct=getEscriptParamInt("PASO_DIRECT")   
+
+have_direct=getEscriptParamInt("PASO_DIRECT")
 
 @unittest.skipIf(not HAVE_RIPLEY, "Ripley module not available")
 @unittest.skipIf(mpisize>1 or have_direct!=1, "more than 1 MPI rank or missing direct solver")
@@ -72,8 +72,7 @@ class TestAcousticInversion(unittest.TestCase):
 
         domain=ripRectangle(20,20, diracPoints=[(0.5,1.)], diracTags=['sss'])
         omega=2.
-        
-        
+
         data=Data([1,2], FunctionOnBoundary(domain))
         F=Data([2,3], Function(domain))
         w=1.
@@ -83,7 +82,7 @@ class TestAcousticInversion(unittest.TestCase):
         self.assertRaises(ValueError, AcousticWaveForm, domain, omega, w, Scalar(1, Function(domain)), F) # data is not of shape (2,)
         self.assertRaises(ValueError, AcousticWaveForm, domain, omega, [1,2], data, F) # w is not a scalar
         self.assertRaises(ValueError, AcousticWaveForm, domain, omega, Scalar(1, Function(domain)), data, F) # w is not a scalar
-        
+
         # now we do a real one
         acw=AcousticWaveForm(domain, omega, w, data, F)
         self.assertEqual(acw.getDomain(),  domain)
@@ -93,25 +92,22 @@ class TestAcousticInversion(unittest.TestCase):
         self.assertEqual(pde.getNumSolutions(), 2)
         self.assertEqual(pde.getDomain(),  domain)
 
-        
     def test_numeric2DscaleF(self):
-         
         domain=ripRectangle(100,100, diracPoints=[(0.5,1.)], diracTags=['sss'])
         omega=2.
-        
+
         # test solution is u = a * z where a is complex
         a=complex(3.45, 0.56)
         sigma=complex(1e-3, 0.056)
-        
-        
+
         data=Data([a.real, a.imag], FunctionOnBoundary(domain))
         mydata=data.copy()
-        
+
         z=FunctionOnBoundary(domain).getX()[1]
         w=whereZero(z-1.)
         # source:
         F=Data( [1,0],Function(domain))
-        # 
+
         acw=AcousticWaveForm(domain, omega, w, data, F, coordinates=None, fixAtBottom=False, tol=1e-8, saveMemory=True, scaleF=True)
         # check rescaled data
         surv=acw.getSurvey()
@@ -120,7 +116,7 @@ class TestAcousticInversion(unittest.TestCase):
         mydata_scale=sqrt( integrate(w*length(mydata)**2) )
         self.assertAlmostEqual( acw.getSourceScaling(z*[1, 0.]) , a/mydata_scale )
         self.assertAlmostEqual( acw.getSourceScaling(mydata) , 1./mydata_scale )
-        
+
         # this should be zero:
         sigma_comps=[sigma.real, sigma.imag]
         args=acw.getArguments(sigma_comps)
@@ -131,22 +127,22 @@ class TestAcousticInversion(unittest.TestCase):
         dg=acw.getGradient(sigma_comps, *args)
         self.assertTrue(isinstance(dg, Data))
         self.assertTrue(dg.getShape()==(2,))
-        self.assertTrue(dg.getFunctionSpace()==Solution(domain))                 
-        self.assertTrue(Lsup(dg) < 1e-10)
+        self.assertTrue(dg.getFunctionSpace()==Solution(domain))
+        self.assertLess(Lsup(dg), 1e-10)
 
         # this shuld be zero' too
         sigma_comps=[2*sigma.real, sigma.imag/2.]
         args=acw.getArguments(sigma_comps)
         d=acw.getDefect(sigma_comps, *args)
         self.assertTrue(isinstance(d, float))
-        self.assertTrue(abs(d)< 1e-10)
-        
+        self.assertLess(abs(d), 1e-10)
+
         dg=acw.getGradient(sigma_comps, *args)
         self.assertTrue(isinstance(dg, Data))
         self.assertTrue(dg.getShape()==(2,))
-        self.assertTrue(dg.getFunctionSpace()==Solution(domain))                 
-        self.assertTrue(Lsup(dg) < 1e-10)
-        
+        self.assertTrue(dg.getFunctionSpace()==Solution(domain))
+        self.assertLess(Lsup(dg), 1e-10)
+
         # this shouldn't be zero:
         sigma0=[2*sigma.real, 10*a.imag]*(27*Function(domain).getX()[0]-Function(domain).getX()[1])
         args=acw.getArguments(sigma0)
@@ -154,44 +150,41 @@ class TestAcousticInversion(unittest.TestCase):
         self.assertTrue(isinstance(d0, float))
         self.assertTrue(d0 >= 0)
         self.assertTrue(d0 > 1e-10)
-        
+
         dg0=acw.getGradient(sigma0, *args)
         self.assertTrue(isinstance(dg0, Data))
         self.assertTrue(dg0.getShape()==(2,))
         self.assertTrue(dg0.getFunctionSpace()==Solution(domain))
         self.assertTrue(Lsup(dg0) > 1e-10)
-        
+
         # test the gradient numerrically:
         h=0.002
         X=Function(domain).getX()
         # .. increment:
         p=h*exp(-(length(X-[0.6,0.6])/10)**2)*Lsup(length(sigma0))
 
-        
         sigma1=sigma0+p*[1,0]
         args=acw.getArguments(sigma1)
         d1=acw.getDefect(sigma1, *args)
-        self.assertTrue( abs( d1-d0-integrate(dg0[0]*p) ) < 1e-2  * abs(d1-d0) )
+        self.assertLess( abs( d1-d0-integrate(dg0[0]*p) ), 1e-2*abs(d1-d0) )
 
         sigma2=sigma0+p*[0,1]
         args=acw.getArguments(sigma2)
         d2=acw.getDefect(sigma2, *args)
-        self.assertTrue( abs(d2-d0-integrate(dg0[1]*p))  < 1e-2  * abs(d2-d0) )
-    
+        self.assertLess( abs(d2-d0-integrate(dg0[1]*p)), 1e-2*abs(d2-d0) )
+
     def test_numeric2DnoscaleF(self):
-         
         domain=ripRectangle(10,20, diracPoints=[(0.5,1.)], diracTags=['sss'])
         omega=1.5
-        
+
         # test solution is u = a * z where a is complex
         a=complex(3.45, 0.56)
         sigma=complex(1e-3, 0.056)
-        
-        
+
         data=Data([a.real, a.imag], FunctionOnBoundary(domain))
         z=FunctionOnBoundary(domain).getX()[1]
         w=whereZero(z-1.)
-        # F = - a*omega* sigma 
+        # F = - a*omega* sigma
         F=Data( [-(a*omega**2*sigma).real, -(a*omega**2*sigma).imag ],Function(domain))
 
         acw=AcousticWaveForm(domain, omega, w, data, F, coordinates=None, fixAtBottom=False, tol=1e-8, saveMemory=True, scaleF=False)
@@ -200,16 +193,15 @@ class TestAcousticInversion(unittest.TestCase):
         args=acw.getArguments(sigma_comps)
         d=acw.getDefect(sigma_comps, *args)
         self.assertTrue(isinstance(d, float))
-        self.assertTrue(Lsup(d) < 1e-10)
+        self.assertLess(Lsup(d), 1e-10)
         #self.assertTrue(d >= 0)
-        #self.assertTrue(d < 1e-10)
-        
+
         dg=acw.getGradient(sigma_comps, *args)
 
         self.assertTrue(isinstance(dg, Data))
         self.assertTrue(dg.getShape()==(2,))
-        self.assertTrue(dg.getFunctionSpace()==Solution(domain))                 
-        self.assertTrue(Lsup(dg) < 5e-10)
+        self.assertTrue(dg.getFunctionSpace()==Solution(domain))
+        self.assertLess(Lsup(dg), 5e-10)
         # this shouldn't be zero:
         sigma0=Data([2*sigma.real, sigma.imag/2], Function(domain) )
         args=acw.getArguments(sigma0)
@@ -217,232 +209,92 @@ class TestAcousticInversion(unittest.TestCase):
         self.assertTrue(isinstance(d0, float))
         self.assertTrue(d0 >= 0)
         self.assertTrue(d0 > 1e-10)
-        
+
         dg0=acw.getGradient(sigma0, *args)
         self.assertTrue(isinstance(dg0, Data))
         self.assertTrue(dg0.getShape()==(2,))
         self.assertTrue(dg0.getFunctionSpace()==Solution(domain))
         self.assertTrue(Lsup(dg0) > 1e-10)
-        # test the gradient numerrically:
+        # test the gradient numerically:
         h=0.001
         X=Function(domain).getX()
         p=h*sin(length(X)*np.pi)*Lsup(length(sigma0))
-        
+
         sigma1=sigma0+p*[1,0]
         args=acw.getArguments(sigma1)
         d1=acw.getDefect(sigma1, *args)
 
-        self.assertTrue( abs( d1-d0-integrate(dg0[0]*p) ) < 1e-2  * abs(d1-d0) )
+        self.assertLess( abs( d1-d0-integrate(dg0[0]*p) ), 1e-2*abs(d1-d0) )
 
         sigma2=sigma0+p*[0,1]
         args=acw.getArguments(sigma2)
         d2=acw.getDefect(sigma2, *args)
-        self.assertTrue( abs(d2-d0-integrate(dg0[1]*p))  < 1e-2  * abs(d2-d0) )
-
- at unittest.skipIf(not HAVE_RIPLEY, "Ripley module not available")
-class TestMT2DModelTEMode(unittest.TestCase):
-    def test_API(self):
-        domain=ripRectangle(19, 19, d1=mpisize)
-        omega=2.
-        x=[ [0.2,0.5], [0.3,0.5] ]
-        Z_XY=[ complex(1.2,1.5), complex(1.3,2.5) ]
-        eta=1.
-        w0=1.
-        E_x0=1.
-        # now we do a real one
-        acw=MT2DModelTEMode(domain, omega, x, Z_XY, eta, w0=w0, E_x0=E_x0)
-        self.assertEqual(acw.getDomain(),  domain)
-        pde=acw.setUpPDE()
-        self.assertIsInstance(pde, LinearPDE)
-        self.assertEqual(pde.getNumEquations(), 2)
-        self.assertEqual(pde.getNumSolutions(), 2)
-        self.assertEqual(pde.getDomain(),  domain)
-
-        # other things that should work 
-        acw=MT2DModelTEMode(domain, omega, x, Z_XY, eta=[1.,1.], w0=[2.,3.], E_x0=complex(4.5,6) )
-
-        # these shouldn't work
-        self.assertRaises(ValueError, MT2DModelTEMode, domain, omega, x, [3.], eta=[1.,1.], w0=[2.,3.], E_x0=complex(4.5,6) )
-        self.assertRaises(ValueError, MT2DModelTEMode, domain, omega, x, Z_XY, eta=[1.], w0=[2.,3.], E_x0=complex(4.5,6) )
-        self.assertRaises(ValueError, MT2DModelTEMode, domain, omega, [(6.7,5)], Z_XY, eta=[1.,1.], w0=[2.,3.], E_x0=complex(4.5,6) )
+        self.assertLess( abs(d2-d0-integrate(dg0[1]*p)), 1e-2*abs(d2-d0) )
 
-    def test_PDE(self):
-        omega=2.
-        mu0=0.123
-        SIGMA=15.
-        k=cmath.sqrt(1j*omega*mu0*SIGMA)  # Ex=exp(k*z)
-
-        domain=ripRectangle(199,199, d1=mpisize)
-
-        
-        IMP=cmath.sqrt(1j*omega*mu0/SIGMA)
-        Z_XY=[ IMP, IMP ]
-        x=[ [0.3,0.5], [0.6,0.5] ]
-        eta=0.005
-        z=domain.getX()[1]
-        Ex0_ex=exp(-k.real*z)*cos(-k.imag*z)
-        Ex0_ex_z=(-k.real*cos(-k.imag*z)+k.imag*sin(-k.imag*z)) * exp(-k.real*z)
-        Ex1_ex=exp(-k.real*z)*sin(-k.imag*z)
-        Ex1_ex_z=(-k.real*sin(-k.imag*z)-k.imag*cos(-k.imag*z)) * exp(-k.real*z)
-
-        acw=MT2DModelTEMode(domain, omega, x, Z_XY, eta, mu=mu0, fixAtBottom=True, E_x0=Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], tol=1e-9)
-
-        args=acw.getArguments(SIGMA)
-        Ex=args[0]
-        Exz=args[1]        
-        self.assertTrue(Lsup(Ex[0]-Ex0_ex) <= 1e-4 * Lsup(Ex0_ex))
-        self.assertTrue(Lsup(Ex[1]-Ex1_ex) <= 1e-4 * Lsup(Ex1_ex))
-        self.assertTrue(Lsup(Exz[0]-Ex0_ex_z) <= 1e-2 * Lsup(Ex0_ex_z))
-        self.assertTrue(Lsup(Exz[1]-Ex1_ex_z) <= 1e-2 * Lsup(Ex1_ex_z))
-
-        argsr=acw.getArguments(0.)
-        ref=acw.getDefect(0., *argsr)
-        
-        # this should be almost zero:
-        args=acw.getArguments(SIGMA)
-        d=acw.getDefect(SIGMA, *args)
-        
-        self.assertTrue( d > 0.)
-        self.assertTrue( ref > 0.)
-        self.assertTrue( d <= 1e-4 * ref ) # d should be zero (some sort of)  
-
-        # and this should be zero        
-        d0=acw.getDefect(SIGMA, Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], Ex0_ex_z*[1.,0]+ Ex1_ex_z*[0,1.])
-        self.assertTrue( d0 <= 1e-8 * ref ) # d should be zero (some sort of)  
-        
-
-        # and this too
-        dg=acw.getGradient(SIGMA, Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], Ex0_ex_z*[1.,0]+ Ex1_ex_z*[0,1.])
-        self.assertTrue(isinstance(dg, Data))
-        self.assertTrue(dg.getShape()==())              
-        self.assertTrue(Lsup(dg) < 1e-10)
-        
-    def test_Differential(self):
-    
-        INC=0.01 
-        
-        omega=2.
-        mu0=0.123
-        SIGMA=15.
-        k=cmath.sqrt(1j*omega*mu0*SIGMA)  # Ex=exp(k*z)
-
-        domain=ripRectangle(99,99, d1=mpisize)
-
-        
-        IMP=-cmath.sqrt(1j*omega*mu0/SIGMA)
-        Z_XY=[ IMP, IMP ]
-        x=[ [0.3,0.5], [0.6,0.5] ]
-        eta=0.005
-        z=domain.getX()[1]
-        Ex0_ex=exp(-k.real*z)*cos(-k.imag*z)
-        Ex0_ex_z=(-k.real*cos(-k.imag*z)+k.imag*sin(-k.imag*z)) * exp(-k.real*z)
-        Ex1_ex=exp(-k.real*z)*sin(-k.imag*z)
-        Ex1_ex_z=(-k.real*sin(-k.imag*z)-k.imag*cos(-k.imag*z)) * exp(-k.real*z)
-
-        acw=MT2DModelTEMode(domain, omega, x, Z_XY, eta, mu=mu0, fixAtBottom=True, E_x0=Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], tol=1e-9 )
-    
-        # this is the base line:
-        SIGMA0=10.        
-        args0=acw.getArguments(SIGMA0)
-        d0=acw.getDefect(SIGMA0, *args0)
-        
-        dg0=acw.getGradient(SIGMA0, *args0)
-        self.assertTrue(isinstance(dg0, Data))
-        self.assertTrue(dg0.getShape()==())
-        
-        
-        X=Function(domain).getX()
-
-        # test 1
-        p=INC
-        SIGMA1=SIGMA0+p
-        args1=acw.getArguments(SIGMA1)
-        d1=acw.getDefect(SIGMA1, *args1)
-        self.assertTrue( abs( d1-d0-integrate(dg0*p) ) < 1e-2  * abs(d1-d0) )
-                
-        # test 2
-        p=exp(-length(X-(0.2,0.2))**2/10)*INC
-        SIGMA1=SIGMA0+p
-        args1=acw.getArguments(SIGMA1)
-        d1=acw.getDefect(SIGMA1, *args1)
-        self.assertTrue( abs( d1-d0-integrate(dg0*p) ) < 1e-2  * abs(d1-d0) )
-
-        # test 3
-        p=sin(length(X)*3*3.14)*INC
-        SIGMA1=SIGMA0+p
-        args1=acw.getArguments(SIGMA1)
-        d1=acw.getDefect(SIGMA1, *args1)
-        self.assertTrue( abs( d1-d0-integrate(dg0*p) ) < 1e-2  * abs(d1-d0) )
 
 @unittest.skipIf(not HAVE_RIPLEY, "Ripley module not available")
 class TestSubsidence(unittest.TestCase):
     def test_PDE(self):
-         
         lam=2.
         mu=1.
 
         domain=ripBrick(20,20,19, d2=mpisize)
-        
+
         xb=FunctionOnBoundary(domain).getX()
         m=whereZero(xb[2]-1)
         w=m*[0,0,1]
         d=m*2.5
         acw=Subsidence(domain, w,d, lam, mu )
-        
-        P0=10.        
+
+        P0=10.
         args0=acw.getArguments(P0)
         u=args0[0]
-        self.assertTrue(Lsup(u[0]) < 1.e-8)
-        self.assertTrue(Lsup(u[1]) < 1.e-8)
-        self.assertTrue(Lsup(u[2]-2.5*domain.getX()[2]) < 1.e-8)
-        
+        self.assertLess(Lsup(u[0]), 1.e-8)
+        self.assertLess(Lsup(u[1]), 1.e-8)
+        self.assertLess(Lsup(u[2]-2.5*domain.getX()[2]), 1.e-8)
+
         dd=acw.getDefect(P0, *args0)
-        
+
         self.assertTrue( dd >= 0.)
         self.assertTrue( dd <= 1e-7 * 2.5 )
+
     def test_Differential(self):
-    
         lam=2.
         mu=1.
-        
-        INC=0.01 
+        INC=0.01
         domain=ripBrick(20,20,20*mpisize-1 , d2=mpisize)
-        
+
         xb=FunctionOnBoundary(domain).getX()
         m=whereZero(xb[2]-1)
         w=m*[0,0,1]
         d=m*2.5
         acw=Subsidence(domain, w,d, lam, mu )
-        
-        
+
         x=Function(domain).getX()
         P0=x[0]*x[1]
         args0=acw.getArguments(P0)
         d0=acw.getDefect(P0, *args0)
         grad_d=acw.getGradient(P0, *args0)
 
-        
         dP=exp(-(length(x-[0.5,0.5,0.5])/0.06)**2)
         P1=P0+INC*dP
         args1=acw.getArguments(P1)
         d1=acw.getDefect(P1, *args1)
         ref=abs((d1-d0)/INC)
-        self.assertTrue(abs((d1-d0)/INC-integrate(grad_d* dP)) < ref * 1.e-5) 
+        self.assertLess(abs((d1-d0)/INC-integrate(grad_d* dP)), ref * 1.e-5)
 
         dP=exp(-(length(x-[0.3,0.3,0.5])/0.06)**2)
         P2=P0-INC*dP
         args2=acw.getArguments(P2)
         d2=acw.getDefect(P2, *args2)
         ref=abs((d2-d0)/INC)
-        self.assertTrue(abs((d2-d0)/INC+integrate(grad_d* dP)) < ref * 1.e-5) 
+        self.assertLess(abs((d2-d0)/INC+integrate(grad_d* dP)), ref * 1.e-5)
 
 @unittest.skipIf(not HAVE_FINLEY, "Finley module not available")
 class TestDCResistivity(unittest.TestCase):
 
     def test_PDE2D(self):
-         
-        dx_tests=0.1 
-
+        dx_tests=0.1
         sigma0=1.
         electrodes=[(0.5-2*dx_tests,1.), (0.5-dx_tests,1.), (0.5+dx_tests,1.), (0.5+2*dx_tests,1.)]
         domain=finRectangle(20,20, d1=mpisize,  diracPoints=electrodes, diracTags=["sl0", "sl1", "sr0", "sr1"] )
@@ -458,7 +310,7 @@ class TestDCResistivity(unittest.TestCase):
         ppde.setValue(A=kronecker(2)*sigma0, q=q, y_dirac=s)
         pp=ppde.getSolution()
         uu=loc(pp)
-        
+
         # arguments for DcRes
         current = 10.
         sourceInfo = [ "sl0",  "sl1" ]
@@ -469,24 +321,23 @@ class TestDCResistivity(unittest.TestCase):
 
         uuscale=1-current*sigma0/sigmaPrimary
         delphi_in = [ (uu[1]-uu[0]) * uuscale]
-        
+
         acw=DcRes(domain, loc, delphi_in, sampleTags,  phiPrimary, sigmaPrimary)
 
-        self.assertTrue(Lsup(phiPrimary-acw.getPrimaryPotential()) < 1.e-10 * Lsup(acw.getPrimaryPotential()))
+        self.assertLess(Lsup(phiPrimary-acw.getPrimaryPotential()), 1.e-10 * Lsup(acw.getPrimaryPotential()))
 
-        SIGMA=10. # matches current        
+        SIGMA=10. # matches current
         args0=acw.getArguments(SIGMA)
         p=args0[0]
         u=args0[1]
 
         # true secondary potential
         pps=pp-phiPrimary
-        self.assertTrue(Lsup(p-pps) < 1.e-6 * Lsup(pps))
-
+        self.assertLess(Lsup(p-pps), 1.e-6*Lsup(pps))
 
         # test return values at electrodes:
-        self.assertTrue(abs(u[0]-uu[0]*uuscale) < 1.e-6 * abs(uu[0]*uuscale))
-        self.assertTrue(abs(u[1]-uu[1]*uuscale) < 1.e-6 * abs(uu[1]*uuscale))
+        self.assertLess(abs(u[0]-uu[0]*uuscale), 1.e-6 * abs(uu[0]*uuscale))
+        self.assertLess(abs(u[1]-uu[1]*uuscale), 1.e-6 * abs(uu[1]*uuscale))
 
         # this sould be zero
         dd=acw.getDefect(SIGMA, *args0)
@@ -494,11 +345,9 @@ class TestDCResistivity(unittest.TestCase):
         self.assertTrue( dd <= 1e-7 )
 
     def test_Differential2D(self):
-
         INC=0.001
-
         sigma0=1.
-        dx_tests=0.1 
+        dx_tests=0.1
         electrodes=[(0.5-2*dx_tests,1.), (0.5-dx_tests,1.), (0.5+dx_tests,1.), (0.5+2*dx_tests,1.)]
         domain=finRectangle(20,20, d1=mpisize,  diracPoints=electrodes, diracTags=["sl0", "sl1", "sr0", "sr1"] )
         loc=Locator(domain,electrodes[2:])
@@ -515,40 +364,40 @@ class TestDCResistivity(unittest.TestCase):
 
         acw=DcRes(domain, loc, delphi_in, sampleTags,  phiPrimary, sigmaPrimary)
 
-        #===========================================================================
+        #=====================================================================
         x=Function(domain).getX()
         SIGMA0=x[0]*x[1]+1
         args0=acw.getArguments(SIGMA0)
         d0=acw.getDefect(SIGMA0, *args0)
         grad_d=acw.getGradient(SIGMA0, *args0)
-        
+
         dS=exp(-(length(x-[0.5,0.5])/0.2)**2)
         SIGMA1=SIGMA0+INC*dS
         args1=acw.getArguments(SIGMA1)
         d1=acw.getDefect(SIGMA1, *args1)
         ref=abs((d1-d0)/INC)
-        self.assertTrue(abs((d1-d0)/INC-integrate(grad_d* dS)) < ref * 1.e-3) 
+        self.assertLess(abs((d1-d0)/INC-integrate(grad_d* dS)), ref * 1.e-3)
 
         dS=-exp(-(length(x-[0.5,0.5])/0.2)**2)
         SIGMA2=SIGMA0+INC*dS
         args2=acw.getArguments(SIGMA2)
         d2=acw.getDefect(SIGMA2, *args2)
         ref=abs((d2-d0)/INC)
-        self.assertTrue(abs((d2-d0)/INC-integrate(grad_d* dS)) < ref * 1.e-3) 
+        self.assertLess(abs((d2-d0)/INC-integrate(grad_d* dS)), ref * 1.e-3)
 
         dS=-1
         SIGMA3=SIGMA0+INC*dS
         args3=acw.getArguments(SIGMA3)
         d3=acw.getDefect(SIGMA3, *args3)
         ref=abs((d3-d0)/INC)
-        self.assertTrue(abs((d3-d0)/INC-integrate(grad_d* dS)) < ref * 1.e-3) 
+        self.assertLess(abs((d3-d0)/INC-integrate(grad_d* dS)), ref * 1.e-3)
 
         dS=1
         SIGMA4=SIGMA0+INC*dS
         args4=acw.getArguments(SIGMA4)
         d4=acw.getDefect(SIGMA4, *args4)
         ref=abs((d4-d0)/INC)
-        self.assertTrue(abs((d4-d0)/INC-integrate(grad_d* dS)) < ref * 1.e-3) 
+        self.assertLess(abs((d4-d0)/INC-integrate(grad_d* dS)), ref * 1.e-3)
 
 class TestIsostaticPressure(unittest.TestCase):
     @unittest.skipIf(not HAVE_RIPLEY, "Ripley module not available")
@@ -556,25 +405,320 @@ class TestIsostaticPressure(unittest.TestCase):
         domain=ripBrick(50,50,20*mpisize-1, d2=mpisize)
 
         ps=IsostaticPressure(domain, level0=1., coordinates=None)
-    
         g=Vector(0., Function(domain))
         rho=Scalar(100, Function(domain))
         p0=ps.getPressure(g, rho)
         p_ref=-(1.-domain.getX()[2])*981.
-        self.assertTrue(Lsup(p0-p_ref) < 1e-6 * Lsup(p_ref))
+        self.assertLess(Lsup(p0-p_ref), 1e-6 * Lsup(p_ref))
 
         g=Vector([0,0,-10], Function(domain))
         rho=Scalar(0, Function(domain))
         p0=ps.getPressure(g, rho)
         p_ref=-(1.-domain.getX()[2])*26700
-        self.assertTrue(Lsup(p0-p_ref) < 1e-6 * Lsup(p_ref))
+        self.assertLess(Lsup(p0-p_ref), 1e-6 * Lsup(p_ref))
 
         g=Vector([0,0,-10], Function(domain))
         rho=Scalar(100, Function(domain))
         p0=ps.getPressure(g, rho)
         p_ref=-(1.-domain.getX()[2])*(981.+26700+1000)
-        self.assertTrue(Lsup(p0-p_ref) < 1e-6 * Lsup(p_ref))
-                               
+        self.assertLess(Lsup(p0-p_ref), 1e-6 * Lsup(p_ref))
+
+ at unittest.skipIf(not HAVE_RIPLEY, "Ripley module not available")
+ at unittest.skipIf(mpisize>1 or have_direct!=1, "more than 1 MPI rank or missing direct solver")
+class TestMT2DModelTEMode(unittest.TestCase):
+    def test_API(self):
+        domain=ripRectangle(25, 25, d1=mpisize)
+        omega=2.
+        x=[ [0.2,0.5], [0.3,0.5] ]
+        Z_XY=[ complex(1.2,1.5), complex(1.3,2.5) ]
+        eta=1.
+        w0=1.
+        Ex0=1.
+        # now we do a real one
+        model=MT2DModelTEMode(domain, omega, x, Z_XY, eta, w0=w0, Ex_top=Ex0)
+        self.assertEqual(model.getDomain(),  domain)
+        pde=model.setUpPDE()
+        self.assertIsInstance(pde, LinearPDE)
+        self.assertEqual(pde.getNumEquations(), 2)
+        self.assertEqual(pde.getNumSolutions(), 2)
+        self.assertEqual(pde.getDomain(),  domain)
+
+        # other things that should work
+        model=MT2DModelTEMode(domain, omega, x, Z_XY, eta=None, w0=[2.,3.], Ex_top=complex(4.5,6) )
+
+        # these shouldn't work
+        self.assertRaises(ValueError, MT2DModelTEMode, domain, omega, x, [3.], eta=[1.,1.], w0=[2.,3.], Ex_top=complex(4.5,6) )
+        self.assertRaises(ValueError, MT2DModelTEMode, domain, omega, x, Z_XY, eta=[1.], w0=[2.,3.], Ex_top=complex(4.5,6) )
+        self.assertRaises(ValueError, MT2DModelTEMode, domain, omega, [(6.7,5)], Z_XY, eta=[1.,1.], w0=[2.,3.], Ex_top=complex(4.5,6) )
+
+    def test_PDE(self):
+        omega=1.
+        mu0=0.123
+        SIGMA=15.
+        k=cmath.sqrt(1j*omega*mu0*SIGMA)  # Ex=exp(k*z)
+        NE=101
+        domain=ripRectangle(NE,NE, d1=mpisize)
+
+        Z0=0.5
+        H=1./NE
+        X1=(int(0.3/H)+0.5)*H
+        X2=(int(0.6/H)+0.5)*H
+
+        IMP=-(1j*omega*mu0)/k*(cmath.exp(k*Z0)-cmath.exp(-k*Z0))/(cmath.exp(k*Z0)+cmath.exp(-k*Z0))
+        Z_XY=[ IMP, IMP ]
+
+        x=[ [X1,Z0], [X2,Z0] ]
+        eta=None
+
+        z=domain.getX()[1]
+        Ex0_ex=cos(k.imag*z)*(exp(k.real*z)-exp(-k.real*z))
+        Ex0_ex_z=-sin(k.imag*z)*k.imag*(exp(k.real*z)-exp(-k.real*z))+cos(k.imag*z)*(exp(k.real*z)+exp(-k.real*z))*k.real
+        Ex1_ex=sin(k.imag*z)*(exp(k.real*z)+exp(-k.real*z))
+        Ex1_ex_z=cos(k.imag*z)*k.imag*(exp(k.real*z)+exp(-k.real*z))+sin(k.imag*z)*(exp(k.real*z)-exp(-k.real*z))*k.real
+
+        model=MT2DModelTEMode(domain, omega, x, Z_XY, eta, mu=mu0, fixAtTop=True, Ex_top=Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], tol=1e-9,  directSolver=True)
+
+        args=model.getArguments(SIGMA)
+        Ex=args[0]
+        Exz=args[1]
+        self.assertTrue(Lsup(Ex[0]-Ex0_ex) <= 1e-4 * Lsup(Ex0_ex))
+        self.assertTrue(Lsup(Ex[1]-Ex1_ex) <= 1e-4 * Lsup(Ex1_ex))
+        self.assertTrue(Lsup(Exz[0]-Ex0_ex_z) <= 1e-2 * Lsup(Ex0_ex_z))
+        self.assertTrue(Lsup(Exz[1]-Ex1_ex_z) <= 1e-2 * Lsup(Ex1_ex_z))
+
+        argsr=model.getArguments(0.)
+        ref=model.getDefect(0., *argsr)
+
+        # this should be almost zero:
+        args=model.getArguments(SIGMA)
+        d=model.getDefect(SIGMA, *args)
+        self.assertTrue( d > 0.)
+        self.assertTrue( ref > 0.)
+        self.assertTrue( d <= 3e-3 * ref ) # d should be zero (some sort of)
+
+        z=ReducedFunction(domain).getX()[1]
+        Ex0_ex=cos(k.imag*z)*(exp(k.real*z)-exp(-k.real*z))
+        Ex1_ex=sin(k.imag*z)*(exp(k.real*z)+exp(-k.real*z))
+        Ex0_ex_z=-sin(k.imag*z)*k.imag*(exp(k.real*z)-exp(-k.real*z))+cos(k.imag*z)*(exp(k.real*z)+exp(-k.real*z))*k.real
+        Ex1_ex_z=cos(k.imag*z)*k.imag*(exp(k.real*z)+exp(-k.real*z))+sin(k.imag*z)*(exp(k.real*z)-exp(-k.real*z))*k.real
+        # and this should be zero
+        d0=model.getDefect(SIGMA, Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], Ex0_ex_z*[1.,0]+ Ex1_ex_z*[0,1.])
+        self.assertTrue( d0 <= 1e-8 * ref ) # d should be zero (some sort of)
+
+        # and this too
+        dg=model.getGradient(SIGMA, Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], Ex0_ex_z*[1.,0]+ Ex1_ex_z*[0,1.])
+        self.assertTrue(isinstance(dg, Data))
+        self.assertTrue(dg.getShape()==())
+        self.assertLess(Lsup(dg), 1e-10)
+
+    def test_Differential(self):
+        INC=0.001
+        omega=5.
+        mu0=0.123
+        SIGMA=15.
+        k=cmath.sqrt(1j*omega*mu0*SIGMA)  # Ex=exp(k*z)
+
+        NE=101
+        domain=ripRectangle(NE,NE, d1=mpisize)
+
+        Z0=0.5
+        IMP=-(1j*omega*mu0)/k*(cmath.exp(k*Z0)-cmath.exp(-k*Z0))/(cmath.exp(k*Z0)+cmath.exp(-k*Z0))
+        Z_XY=[ IMP, IMP ]
+        H=1./NE
+        X1=(int(0.3/H)+0.5)*H
+        X2=(int(0.6/H)+0.5)*H
+        x=[ [X1,Z0], [X2,Z0] ]
+        eta=None
+
+        z=domain.getX()[1]
+        Ex0_ex=cos(k.imag*z)*(exp(k.real*z)-exp(-k.real*z))
+        Ex0_ex_z=-sin(k.imag*z)*k.imag*(exp(k.real*z)-exp(-k.real*z))+cos(k.imag*z)*(exp(k.real*z)+exp(-k.real*z))*k.real
+        Ex1_ex=sin(k.imag*z)*(exp(k.real*z)+exp(-k.real*z))
+        Ex1_ex_z=cos(k.imag*z)*k.imag*(exp(k.real*z)+exp(-k.real*z))+sin(k.imag*z)*(exp(k.real*z)-exp(-k.real*z))*k.real
+
+        model=MT2DModelTEMode(domain, omega, x, Z_XY, eta, mu=mu0, fixAtTop=True, Ex_top=Ex0_ex*[1.,0]+ Ex1_ex*[0,1.], tol=1e-9,  directSolver=True)
+
+        # this is the base line:
+        xx=domain.getX()[0]
+        SIGMA0=3.*(xx+0.3)
+        args0=model.getArguments(SIGMA0)
+        d0=model.getDefect(SIGMA0, *args0)
+        dg0=model.getGradient(SIGMA0, *args0)
+        self.assertTrue(isinstance(dg0, Data))
+        self.assertTrue(dg0.getShape()==())
+
+        X=Function(domain).getX()
+
+        # test 1
+        p=INC
+        SIGMA1=SIGMA0+p
+        args1=model.getArguments(SIGMA1)
+        d1=model.getDefect(SIGMA1, *args1)
+        self.assertLess( abs( d1-d0-integrate(dg0*p) ), 1e-2*abs(d1-d0) )
+
+        # test 2
+        p=exp(-length(X-(0.2,0.2))**2/10)*INC
+        SIGMA1=SIGMA0+p
+        args1=model.getArguments(SIGMA1)
+        d1=model.getDefect(SIGMA1, *args1)
+        self.assertLess( abs( d1-d0-integrate(dg0*p) ), 1e-2*abs(d1-d0) )
+
+        # test 3
+        p=sin(length(X)*3*3.14)*INC
+        SIGMA1=SIGMA0+p
+        args1=model.getArguments(SIGMA1)
+        d1=model.getDefect(SIGMA1, *args1)
+        self.assertLess( abs( d1-d0-integrate(dg0*p) ), 1e-2*abs(d1-d0) )
+
+
+ at unittest.skipIf(not HAVE_RIPLEY, "Ripley module not available")
+ at unittest.skipIf(mpisize>1 or have_direct!=1, "more than 1 MPI rank or missing direct solver")
+class TestMT2DModelTMMode(unittest.TestCase):
+    def test_API(self):
+        domain=ripRectangle(25, 25, d0=mpisize)
+        omega=2.
+        x=[ [0.2,0.5], [0.3,0.5] ]
+        Z_XY=[ complex(1.2,1.5), complex(1.3,2.5) ]
+        eta=1.
+        w0=1.
+        Hx0=1.
+        # now we do a real one
+        model=MT2DModelTMMode(domain, omega, x, Z_XY, eta, w0=w0, Hx_bottom=Hx0)
+        self.assertEqual(model.getDomain(),  domain)
+        pde=model.setUpPDE()
+        self.assertIsInstance(pde, LinearPDE)
+        self.assertEqual(pde.getNumEquations(), 2)
+        self.assertEqual(pde.getNumSolutions(), 2)
+        self.assertEqual(pde.getDomain(),  domain)
+
+        # other things that should work
+        model=MT2DModelTMMode(domain, omega, x, Z_XY, eta=None, w0=[2.,3.], Hx_bottom=complex(4.5,6) )
+
+        # these shouldn't work
+        self.assertRaises(ValueError, MT2DModelTMMode, domain, omega, x, [3.], eta=[1.,1.], w0=[2.,3.], Hx_bottom=complex(4.5,6) )
+        self.assertRaises(ValueError, MT2DModelTMMode, domain, omega, x, Z_XY, eta=[1.], w0=[2.,3.], Hx_bottom=complex(4.5,6) )
+        self.assertRaises(ValueError, MT2DModelTMMode, domain, omega, [(6.7,5)], Z_XY, eta=[1.,1.], w0=[2.,3.], Hx_bottom=complex(4.5,6) )
+
+    def test_PDE(self):
+        omega=10.
+        mu0=0.123
+        RHO=0.15
+        k=cmath.sqrt(1j*omega*mu0/RHO)  # Hx=exp(k*z)
+        NE=101
+        L=1
+        domain=ripRectangle(NE,NE, d0=mpisize)
+
+        Z0=0.5
+        H=1./NE
+        X1=(int(0.3/H)+0.5)*H
+        X2=(int(0.6/H)+0.5)*H
+
+        IMP=RHO*k*(cmath.exp(k*(Z0-L))-cmath.exp(-k*(Z0-L)))/(cmath.exp(k*(Z0-L))+cmath.exp(-k*(Z0-L)))
+        Z_XY=[ IMP, IMP ]
+
+        x=[ [X1,Z0], [X2,Z0] ]
+        eta=None
+
+        z=domain.getX()[1]
+        Hx0_ex=cos(k.imag*(z-L))*(exp(k.real*(z-L))+exp(-k.real*(z-L)))/2
+        Hx0_ex_z=(-sin(k.imag*(z-L))*k.imag*(exp(k.real*(z-L))+exp(-k.real*(z-L)))+cos(k.imag*(z-L))*(exp(k.real*(z-L))-exp(-k.real*(z-L)))*k.real)/2
+        Hx1_ex=sin(k.imag*(z-L))*(exp(k.real*(z-L))-exp(-k.real*(z-L)))/2
+        Hx1_ex_z=(cos(k.imag*(z-L))*k.imag*(exp(k.real*(z-L))-exp(-k.real*(z-L)))+sin(k.imag*(z-L))*(exp(k.real*(z-L))+exp(-k.real*(z-L)))*k.real)/2
+
+        model=MT2DModelTMMode(domain, omega, x, Z_XY, eta, mu=mu0, fixAtBottom=True, Hx_bottom=Hx0_ex*[1.,0]+ Hx1_ex*[0,1.], tol=1e-9,  directSolver=True)
+
+        args=model.getArguments(RHO)
+        Hx=args[0]
+        g_Hx=args[1]
+        Hxz=g_Hx[:,1]
+        self.assertLess(Lsup(Hx[0]-Hx0_ex), 1e-4 * Lsup(Hx0_ex))
+        self.assertLess(Lsup(Hx[1]-Hx1_ex), 1e-4 * Lsup(Hx1_ex))
+        self.assertLess(Lsup(Hxz[0]-Hx0_ex_z), 1e-2 * Lsup(Hx0_ex_z))
+        self.assertLess(Lsup(Hxz[1]-Hx1_ex_z), 1e-2 * Lsup(Hx1_ex_z))
+
+        argsr=model.getArguments(1.)
+        ref=model.getDefect(1., *argsr)
+
+        # this should be almost zero:
+        args=model.getArguments(RHO)
+        d=model.getDefect(RHO, *args)
+        self.assertTrue( d > 0.)
+        self.assertTrue( ref > 0.)
+        self.assertTrue( d <= 3e-3 * ref ) # d should be zero (some sort of)
+
+        z=ReducedFunction(domain).getX()[1]
+        Hx0_ex=cos(k.imag*(z-L))*(exp(k.real*(z-L))+exp(-k.real*(z-L)))/2
+        Hx0_ex_z=(-sin(k.imag*(z-L))*k.imag*(exp(k.real*(z-L))+exp(-k.real*(z-L)))+cos(k.imag*(z-L))*(exp(k.real*(z-L))-exp(-k.real*(z-L)))*k.real)/2
+        Hx1_ex=sin(k.imag*(z-L))*(exp(k.real*(z-L))-exp(-k.real*(z-L)))/2
+        Hx1_ex_z=(cos(k.imag*(z-L))*k.imag*(exp(k.real*(z-L))-exp(-k.real*(z-L)))+sin(k.imag*(z-L))*(exp(k.real*(z-L))+exp(-k.real*(z-L)))*k.real)/2
+        g_Hx = Data(0, (2,2), Hx0_ex_z.getFunctionSpace())
+        g_Hx[0,1] = Hx0_ex_z
+        g_Hx[1,1] = Hx1_ex_z
+        # and this should be zero
+        d0=model.getDefect(RHO, Hx0_ex*[1.,0]+ Hx1_ex*[0,1.], g_Hx)
+        self.assertLess( d0, 1e-8 * ref ) # d should be zero (some sort of)
+
+        # and this too
+        dg=model.getGradient(RHO, Hx0_ex*[1.,0]+Hx1_ex*[0,1.], g_Hx)
+        self.assertTrue(isinstance(dg, Data))
+        self.assertTrue(dg.getShape()==())
+        self.assertLess(Lsup(dg), 1e-10)
+
+    def test_Differential(self):
+        INC=0.001
+        omega=5.
+        mu0=0.123
+        RHO=0.15
+        k=cmath.sqrt(1j*omega*mu0*1/RHO)  # Hx=exp(k*z)
+
+        L=1
+        NE=101
+        domain=ripRectangle(NE,NE, d0=mpisize)
+
+        Z0=0.5
+        IMP=RHO*k*(cmath.exp(k*(Z0-L))-cmath.exp(-k*(Z0-L)))/(cmath.exp(k*(Z0-L))+cmath.exp(-k*(Z0-L)))
+        Z_XY=[ IMP, IMP ]
+        H=1./NE
+        X1=(int(0.3/H)+0.5)*H
+        X2=(int(0.6/H)+0.5)*H
+        x=[ [X1,Z0], [X2,Z0] ]
+        eta=None
+
+        model=MT2DModelTMMode(domain, omega, x, Z_XY, eta, mu=mu0, tol=1e-9,  directSolver=True)
+
+        # this is the base line:
+        xx=domain.getX()[0]
+        RHO0=3.*(xx+0.3)
+        args0=model.getArguments(RHO0)
+        d0=model.getDefect(RHO0, *args0)
+        dg0=model.getGradient(RHO0, *args0)
+        self.assertTrue(isinstance(dg0, Data))
+        self.assertTrue(dg0.getShape()==())
+
+        X=Function(domain).getX()
+
+        # test 1
+        p=INC
+        RHO1=RHO0+p
+        args1=model.getArguments(RHO1)
+        d1=model.getDefect(RHO1, *args1)
+        self.assertLess( abs( d1-d0-integrate(dg0*p) ), 1e-2*abs(d1-d0) )
+
+        # test 2
+        p=exp(-length(X-(0.2,0.2))**2/10)*INC
+        RHO1=RHO0+p
+        args1=model.getArguments(RHO1)
+        d1=model.getDefect(RHO1, *args1)
+        self.assertLess( abs( d1-d0-integrate(dg0*p) ), 1e-2*abs(d1-d0) )
+
+        # test 3
+        p=sin(length(X)*3*3.14)*INC
+        RHO1=RHO0+p
+        args1=model.getArguments(RHO1)
+        d1=model.getDefect(RHO1, *args1)
+        self.assertLess( abs( d1-d0-integrate(dg0*p) ), 1e-2*abs(d1-d0) )
+
+
 if __name__ == '__main__':
     run_tests(__name__, exit_on_failure=True)
-    
+
diff --git a/downunder/test/python/run_gravity.py b/downunder/test/python/run_gravity.py
index 4d3e601..911ff25 100644
--- a/downunder/test/python/run_gravity.py
+++ b/downunder/test/python/run_gravity.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@ from __future__ import print_function
 
 """2D gravity inversion example using synthetic data"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_inversion_gravmag_2d.py b/downunder/test/python/run_inversion_gravmag_2d.py
index 4f89540..89d6391 100644
--- a/downunder/test/python/run_inversion_gravmag_2d.py
+++ b/downunder/test/python/run_inversion_gravmag_2d.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@ from __future__ import print_function
 
 """2D magnetic/gravity joint inversion example using synthetic data"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_inversioncostfunction.py b/downunder/test/python/run_inversioncostfunction.py
index 0c40949..0ddc267 100644
--- a/downunder/test/python/run_inversioncostfunction.py
+++ b/downunder/test/python/run_inversioncostfunction.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_magnetic.py b/downunder/test/python/run_magnetic.py
index 48a04fb..ff1ec72 100644
--- a/downunder/test/python/run_magnetic.py
+++ b/downunder/test/python/run_magnetic.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@ from __future__ import print_function
 
 """2D magnetic inversion example using synthetic data"""
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_mappings.py b/downunder/test/python/run_mappings.py
index 5df170f..22b89f9 100644
--- a/downunder/test/python/run_mappings.py
+++ b/downunder/test/python/run_mappings.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_minimizers.py b/downunder/test/python/run_minimizers.py
index 6e0a474..aee9a2d 100644
--- a/downunder/test/python/run_minimizers.py
+++ b/downunder/test/python/run_minimizers.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_regularization.py b/downunder/test/python/run_regularization.py
index 8f37204..0da1694 100644
--- a/downunder/test/python/run_regularization.py
+++ b/downunder/test/python/run_regularization.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/downunder/test/python/run_seismic.py b/downunder/test/python/run_seismic.py
index 4c107e7..5785ed6 100644
--- a/downunder/test/python/run_seismic.py
+++ b/downunder/test/python/run_seismic.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/benchmarks/dudleybench.py b/dudley/benchmarks/dudleybench.py
index 25fbba3..cebff36 100644
--- a/dudley/benchmarks/dudleybench.py
+++ b/dudley/benchmarks/dudleybench.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/benchmarks/runbenchmark.py b/dudley/benchmarks/runbenchmark.py
index 6334dc6..112403c 100755
--- a/dudley/benchmarks/runbenchmark.py
+++ b/dudley/benchmarks/runbenchmark.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/py_src/SConscript b/dudley/py_src/SConscript
index d419e75..2efe84d 100644
--- a/dudley/py_src/SConscript
+++ b/dudley/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/dudley/py_src/__init__.py b/dudley/py_src/__init__.py
index 135a57c..5f5152b 100644
--- a/dudley/py_src/__init__.py
+++ b/dudley/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@
 """A domain meshed with triangles or tetrahedra only. Imports submodules into its namespace
 """
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/py_src/factorywrappers.py b/dudley/py_src/factorywrappers.py
index 7e28c3c..0ec2adc 100644
--- a/dudley/py_src/factorywrappers.py
+++ b/dudley/py_src/factorywrappers.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2014 by University of Queensland
+# Copyright (c) 2014-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2014 by University of Queensland
+__copyright__="""Copyright (c) 2014-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -41,6 +41,8 @@ def Rectangle(n0=1, n1=1, order=1, l0=1.0, l1=1.0, periodic0=False, periodic1=Fa
       args+=[None]
     return __Rectangle_driver(args)
 
+Rectangle.__doc__=__Rectangle_driver.__doc__
+
 def Brick(n0=1, n1=1, n2=1, order=1, l0=1.0, l1=1.0, l2=1.0, periodic0=0, periodic1=0, periodic2=0,
     integrationOrder=-1, reducedIntegrationOrder=-1, useElementsOnFace=0, useFullElementOrder=0,
     optimize=0, **kwargs):
@@ -57,3 +59,5 @@ def Brick(n0=1, n1=1, n2=1, order=1, l0=1.0, l1=1.0, l2=1.0, periodic0=0, period
     else:
       args+=[None]
     return __Brick_driver(args)
+
+Brick.__doc__=__Brick_driver.__doc__
diff --git a/dudley/py_src/readers.py b/dudley/py_src/readers.py
index 0c68500..eb3f772 100644
--- a/dudley/py_src/readers.py
+++ b/dudley/py_src/readers.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/src/Assemble.h b/dudley/src/Assemble.h
index ccf100c..50f2e31 100644
--- a/dudley/src/Assemble.h
+++ b/dudley/src/Assemble.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -28,7 +28,7 @@
 #include "Dudley.h"
 #include "ElementFile.h"
 #include "NodeFile.h"
-#include "escript/DataC.h"
+#include "escript/Data.h"
 #include "paso/SystemMatrix.h"
 
 struct Dudley_Assemble_Parameters {
@@ -54,43 +54,43 @@ typedef struct Dudley_Assemble_Parameters Dudley_Assemble_Parameters;
 
 #define Dudley_Assemble_reducedIntegrationOrder(__in__) ( (getFunctionSpaceType(__in__) == DUDLEY_REDUCED_ELEMENTS) || (getFunctionSpaceType(__in__) == DUDLEY_REDUCED_FACE_ELEMENTS) )
 
-void Dudley_Assemble_PDE(Dudley_NodeFile *, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
-			 escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-			 escriptDataC *);
+void Dudley_Assemble_PDE(Dudley_NodeFile *, Dudley_ElementFile *, paso::SystemMatrix_ptr, escript::Data *,
+			 const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+			 const escript::Data *);
 
 
-void Dudley_Assemble_getAssembleParameters(Dudley_NodeFile *, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
+void Dudley_Assemble_getAssembleParameters(Dudley_NodeFile *, Dudley_ElementFile *, paso::SystemMatrix_ptr, const escript::Data *,
 				    bool, Dudley_Assemble_Parameters *);
-void Dudley_Assemble_PDE_System2_3D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
-				    escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-				    escriptDataC *);
-void Dudley_Assemble_PDE_System2_2D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
-				    escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-				    escriptDataC *);
-void Dudley_Assemble_PDE_System2_1D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix, escriptDataC *,
-				    escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-				    escriptDataC *);
-
-void Dudley_Assemble_PDE_Single2_3D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
-				    escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-				    escriptDataC *);
-void Dudley_Assemble_PDE_Single2_2D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
-				    escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-				    escriptDataC *);
-void Dudley_Assemble_PDE_Single2_1D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *,
-				    escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *, escriptDataC *,
-				    escriptDataC *);
-void Dudley_Assemble_PDE_Points(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escriptDataC *, escriptDataC *, escriptDataC *);
-
-void Dudley_Assemble_NodeCoordinates(Dudley_NodeFile *, escriptDataC *);
-void Dudley_Assemble_setNormal(Dudley_NodeFile *, Dudley_ElementFile *, escriptDataC *);
-void Dudley_Assemble_interpolate(Dudley_NodeFile *, Dudley_ElementFile *, escriptDataC *, escriptDataC *);
-void Dudley_Assemble_gradient(Dudley_NodeFile *, Dudley_ElementFile *, escriptDataC *, escriptDataC *);
-void Dudley_Assemble_integrate(Dudley_NodeFile *, Dudley_ElementFile *, escriptDataC *, double *);
-void Dudley_Assemble_getSize(Dudley_NodeFile *, Dudley_ElementFile *, escriptDataC *);
-void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escriptDataC * out, escriptDataC * in);
-void Dudley_Assemble_CopyElementData(Dudley_ElementFile * elements, escriptDataC * out, escriptDataC * in);
-void Dudley_Assemble_AverageElementData(Dudley_ElementFile * elements, escriptDataC * out, escriptDataC * in);
+void Dudley_Assemble_PDE_System2_3D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escript::Data *,
+				    const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+				    const escript::Data *);
+void Dudley_Assemble_PDE_System2_2D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escript::Data *,
+				    const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+				    const escript::Data *);
+void Dudley_Assemble_PDE_System2_1D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix, const escript::Data *,
+				    escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+				    const escript::Data *);
+
+void Dudley_Assemble_PDE_Single2_3D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escript::Data *,
+				    const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+				    const escript::Data *);
+void Dudley_Assemble_PDE_Single2_2D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escript::Data *,
+				    const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+				    const escript::Data *);
+void Dudley_Assemble_PDE_Single2_1D(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, const escript::Data *,
+				    const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *, const escript::Data *,
+				    const escript::Data *);
+void Dudley_Assemble_PDE_Points(Dudley_Assemble_Parameters, Dudley_ElementFile *, paso::SystemMatrix_ptr, escript::Data *, const escript::Data *, const escript::Data *);
+
+void Dudley_Assemble_NodeCoordinates(Dudley_NodeFile *, escript::Data *);
+void Dudley_Assemble_setNormal(Dudley_NodeFile *, Dudley_ElementFile *, escript::Data *);
+void Dudley_Assemble_interpolate(Dudley_NodeFile *, Dudley_ElementFile *, const escript::Data *, escript::Data *);
+void Dudley_Assemble_gradient(Dudley_NodeFile *, Dudley_ElementFile *, escript::Data *, const escript::Data *);
+void Dudley_Assemble_integrate(Dudley_NodeFile *, Dudley_ElementFile *, const escript::Data *, double *);
+void Dudley_Assemble_getSize(Dudley_NodeFile *, Dudley_ElementFile *, escript::Data *);
+void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escript::Data * out, const escript::Data * in);
+void Dudley_Assemble_CopyElementData(Dudley_ElementFile * elements, escript::Data * out, const escript::Data * in);
+void Dudley_Assemble_AverageElementData(Dudley_ElementFile * elements, escript::Data * out, const escript::Data * in);
 void Dudley_Assemble_addToSystemMatrix(paso::SystemMatrix_ptr in, const dim_t NN_Equa, const index_t * Nodes_Equa, const dim_t num_Equa,
 				       const dim_t NN_Sol, const index_t * Nodes_Sol, const dim_t num_Sol, const double *array);
 
@@ -103,6 +103,6 @@ void Dudley_Assemble_jacobeans_3D(double *, dim_t, dim_t, dim_t, index_t *, doub
 void Dudley_Assemble_jacobeans_3D_M2D_E2D(double *, dim_t, dim_t, dim_t, index_t *, double *, double *abs_D,
 				   double *quadweight, index_t *);
 
-void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escriptDataC * lumpedMat,
-				  escriptDataC * D, const bool useHRZ);
+void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escript::Data * lumpedMat,
+				  const escript::Data * D, const bool useHRZ);
 #endif				/* #ifndef INC_DUDLEY_ASSEMBLE */
diff --git a/dudley/src/Assemble_AverageElementData.cpp b/dudley/src/Assemble_AverageElementData.cpp
index d9e6f85..58bda8d 100644
--- a/dudley/src/Assemble_AverageElementData.cpp
+++ b/dudley/src/Assemble_AverageElementData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -29,7 +32,7 @@
 
 #include "ShapeTable.h"
 
-void Dudley_Assemble_AverageElementData(Dudley_ElementFile * elements, escriptDataC * out, escriptDataC * in)
+void Dudley_Assemble_AverageElementData(Dudley_ElementFile * elements, escript::Data * out, const escript::Data * in)
 {
     dim_t n, q, numElements, numQuad_in, numQuad_out, i;
     __const double *in_array;
diff --git a/dudley/src/Assemble_CopyElementData.cpp b/dudley/src/Assemble_CopyElementData.cpp
index e0dba1d..cac9731 100644
--- a/dudley/src/Assemble_CopyElementData.cpp
+++ b/dudley/src/Assemble_CopyElementData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -28,7 +31,7 @@
 /****************************************************************************************************************************/
 #include "ShapeTable.h"
 
-void Dudley_Assemble_CopyElementData(Dudley_ElementFile * elements, escriptDataC * out, escriptDataC * in)
+void Dudley_Assemble_CopyElementData(Dudley_ElementFile * elements, escript::Data * out, const escript::Data * in)
 {
     dim_t n, q, numElements, numQuad;
     __const double *in_array;
diff --git a/dudley/src/Assemble_CopyNodalData.cpp b/dudley/src/Assemble_CopyNodalData.cpp
index 4fbb774..c6d361f 100644
--- a/dudley/src/Assemble_CopyNodalData.cpp
+++ b/dudley/src/Assemble_CopyNodalData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,13 +20,16 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Util.h"
 #include "Assemble.h"
 #ifdef _OPENMP
 #include <omp.h>
 #endif
 
-void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escriptDataC * out, escriptDataC * in)
+void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escript::Data * out, const escript::Data * in)
 {
     dim_t n, k, l, mpiSize;
     dim_t numComps = getDataPointSize(out);
@@ -250,10 +253,9 @@ void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escriptDataC * out,
 		coupler.reset(new paso::Coupler(nodes->degreesOfFreedomConnector, numComps));
 		if (Esys_noError())
 		{
-		    /* It is not immediately clear whether coupler can be trusted with constant data so I'll assume RW */
-		    /* Also, it holds pointers so it might not be safe to use on lazy data anyway? */
-		    requireWrite(in);
-            coupler->startCollect(getDataRW(in));
+		    /* safe provided coupler->copyAll is called before the pointer in "in" is invalidated */
+		    const_cast<escript::Data*>(in)->resolve();
+		    coupler->startCollect(in->getDataRO());  
 		    recv_buffer = coupler->finishCollect();
 		    upperBound = nodes->degreesOfFreedomDistribution->getMyNumComponents();
 #pragma omp parallel private(n,k)
@@ -280,8 +282,9 @@ void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escriptDataC * out,
 		coupler.reset(new paso::Coupler(nodes->degreesOfFreedomConnector, numComps));
 		if (Esys_noError())
 		{
-		    requireWrite(in);	/* See comment above about coupler and const */
-            coupler->startCollect(getDataRW(in));
+		    /* safe provided coupler->copyAll is called before the pointer in "in" is invalidated */
+		    const_cast<escript::Data*>(in)->resolve();
+		    coupler->startCollect(in->getDataRO());  
 		    recv_buffer = coupler->finishCollect();
 		    upperBound = nodes->degreesOfFreedomDistribution->getMyNumComponents();
 		    requireWrite(out);
@@ -351,8 +354,9 @@ void Dudley_Assemble_CopyNodalData(Dudley_NodeFile * nodes, escriptDataC * out,
 		if (Esys_noError())
 		{
 		    upperBound = nodes->reducedDegreesOfFreedomDistribution->getMyNumComponents();
-		    requireWrite(in);	/* See comment about coupler and const */
-            coupler->startCollect(getDataRW(in));
+		    /* safe provided coupler->copyAll is called before the pointer in "in" is invalidated */
+		    const_cast<escript::Data*>(in)->resolve();
+		    coupler->startCollect(in->getDataRO());  
 		    recv_buffer = coupler->finishCollect();
 		    requireWrite(out);
 #pragma omp parallel private(n,k,l)
diff --git a/dudley/src/Assemble_LumpedSystem.cpp b/dudley/src/Assemble_LumpedSystem.cpp
index aeb08f9..f7e3440 100644
--- a/dudley/src/Assemble_LumpedSystem.cpp
+++ b/dudley/src/Assemble_LumpedSystem.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -34,8 +37,8 @@
 
 /************************************************************************************/
 
-void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escriptDataC * lumpedMat,
-                                  escriptDataC * D, const bool useHRZ)
+void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escript::Data * lumpedMat,
+                                  const escript::Data * D, const bool useHRZ)
 {
 
     bool reducedIntegrationOrder = FALSE, expandedD;
@@ -54,14 +57,14 @@ void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile *
 
     if (nodes == NULL || elements == NULL)
         return;
-    if (isEmpty(lumpedMat) || isEmpty(D))
+    if (lumpedMat->isEmpty() || D->isEmpty())
         return;
-    if (isEmpty(lumpedMat) && !isEmpty(D))
+    if (lumpedMat->isEmpty() && !D->isEmpty())
     {
         Dudley_setError(TYPE_ERROR, "Dudley_Assemble_LumpedSystem: coefficients are non-zero but no lumped matrix is given.");
         return;
     }
-    funcspace = getFunctionSpaceType(D);
+    funcspace = D->getFunctionSpace().getTypeCode();
     /* check if all function spaces are the same */
     if (funcspace == DUDLEY_ELEMENTS)
     {
@@ -105,7 +108,7 @@ void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile *
     /*  check the dimensions: */
     if (p.numEqu == 1)
     {
-        if (!isEmpty(D))
+        if (!D->isEmpty())
         {
             if (!isDataPointShapeEqual(D, 0, dimensions))
             {
@@ -116,7 +119,7 @@ void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile *
     }
     else
     {
-        if (!isEmpty(D))
+        if (!D->isEmpty())
         {
             dimensions[0] = p.numEqu;
             if (!isDataPointShapeEqual(D, 1, dimensions))
@@ -157,7 +160,7 @@ void Dudley_Assemble_LumpedSystem(Dudley_NodeFile * nodes, Dudley_ElementFile *
               
               len_EM_lumpedMat = p.numShapes * p.numEqu;
 
-              expandedD = isExpanded(D);
+              expandedD = D->isExpanded();
               if (!getQuadShape(elements->numDim, reducedIntegrationOrder, &S))
               {
                   Dudley_setError(TYPE_ERROR, "Dudley_Assemble_LumpedSystem: Unable to locate shape function.");
diff --git a/dudley/src/Assemble_NodeCoordinates.cpp b/dudley/src/Assemble_NodeCoordinates.cpp
index 0f37061..3ba6198 100644
--- a/dudley/src/Assemble_NodeCoordinates.cpp
+++ b/dudley/src/Assemble_NodeCoordinates.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Util.h"
 #include "Assemble.h"
 #ifdef _OPENMP
@@ -28,7 +31,7 @@
 
 /************************************************************************************/
 
-void Dudley_Assemble_NodeCoordinates(Dudley_NodeFile * nodes, escriptDataC * x)
+void Dudley_Assemble_NodeCoordinates(Dudley_NodeFile * nodes, escript::Data * x)
 {
     char error_msg[LenErrorMsg_MAX];
     dim_t n;
diff --git a/dudley/src/Assemble_PDE.cpp b/dudley/src/Assemble_PDE.cpp
index 7e26570..325660e 100644
--- a/dudley/src/Assemble_PDE.cpp
+++ b/dudley/src/Assemble_PDE.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -42,6 +42,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #include "esysUtils/blocktimer.h"
@@ -52,9 +55,9 @@
 /************************************************************************************/
 
 void Dudley_Assemble_PDE(Dudley_NodeFile* nodes, Dudley_ElementFile* elements,
-                         paso::SystemMatrix_ptr S, escriptDataC* F,
-                         escriptDataC* A, escriptDataC* B, escriptDataC* C,
-                         escriptDataC* D, escriptDataC* X, escriptDataC* Y)
+                         paso::SystemMatrix_ptr S, escript::Data* F,
+                         const escript::Data* A, const escript::Data* B, const escript::Data* C,
+                         const escript::Data* D, const escript::Data* X, const escript::Data* Y)
 {
     bool reducedIntegrationOrder = false;
     char error_msg[LenErrorMsg_MAX];
diff --git a/dudley/src/Assemble_PDE_Points.cpp b/dudley/src/Assemble_PDE_Points.cpp
index 1d506d3..0146cd3 100644
--- a/dudley/src/Assemble_PDE_Points.cpp
+++ b/dudley/src/Assemble_PDE_Points.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -34,6 +34,8 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "Assemble.h"
 #include "Util.h"
@@ -46,8 +48,8 @@
 
 void  Dudley_Assemble_PDE_Points(Dudley_Assemble_Parameters p,
                                  Dudley_ElementFile* elements,
-                                 paso::SystemMatrix_ptr Mat, escriptDataC* F,
-                                 escriptDataC* d_dirac, escriptDataC* y_dirac) {
+                                 paso::SystemMatrix_ptr Mat, escript::Data* F,
+                                 const escript::Data* d_dirac, const escript::Data* y_dirac) {
 
     index_t color, e, row_index;
     __const double  *d_dirac_p, *y_dirac_p;
diff --git a/dudley/src/Assemble_PDE_Single2_1D.cpp b/dudley/src/Assemble_PDE_Single2_1D.cpp
index e3d0c95..e5a8ecb 100644
--- a/dudley/src/Assemble_PDE_Single2_1D.cpp
+++ b/dudley/src/Assemble_PDE_Single2_1D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/Assemble_PDE_Single2_2D.cpp b/dudley/src/Assemble_PDE_Single2_2D.cpp
index a79203f..8ad1aba 100644
--- a/dudley/src/Assemble_PDE_Single2_2D.cpp
+++ b/dudley/src/Assemble_PDE_Single2_2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -46,9 +49,9 @@
 /************************************************************************************/
 
 void Dudley_Assemble_PDE_Single2_2D(Dudley_Assemble_Parameters p, Dudley_ElementFile * elements,
-				    paso::SystemMatrix_ptr Mat, escriptDataC * F,
-				    escriptDataC * A, escriptDataC * B, escriptDataC * C, escriptDataC * D,
-				    escriptDataC * X, escriptDataC * Y)
+				    paso::SystemMatrix_ptr Mat, escript::Data* F,
+				    const escript::Data* A, const escript::Data* B, const escript::Data* C, const escript::Data* D,
+				    const escript::Data* X, const escript::Data* Y)
 {
 
 #define DIM 2
diff --git a/dudley/src/Assemble_PDE_Single2_3D.cpp b/dudley/src/Assemble_PDE_Single2_3D.cpp
index d67ff38..3345199 100644
--- a/dudley/src/Assemble_PDE_Single2_3D.cpp
+++ b/dudley/src/Assemble_PDE_Single2_3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -44,9 +47,9 @@
 /************************************************************************************/
 
 void Dudley_Assemble_PDE_Single2_3D(Dudley_Assemble_Parameters p, Dudley_ElementFile * elements,
-				    paso::SystemMatrix_ptr Mat, escriptDataC * F,
-				    escriptDataC * A, escriptDataC * B, escriptDataC * C, escriptDataC * D,
-				    escriptDataC * X, escriptDataC * Y)
+				    paso::SystemMatrix_ptr Mat, escript::Data* F,
+				    const escript::Data* A, const escript::Data* B, const escript::Data* C, const escript::Data* D,
+				    const escript::Data* X, const escript::Data* Y)
 {
 
 #define DIM 3
diff --git a/dudley/src/Assemble_PDE_System2_1D.cpp b/dudley/src/Assemble_PDE_System2_1D.cpp
index bd80d37..bde4309 100644
--- a/dudley/src/Assemble_PDE_System2_1D.cpp
+++ b/dudley/src/Assemble_PDE_System2_1D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/Assemble_PDE_System2_2D.cpp b/dudley/src/Assemble_PDE_System2_2D.cpp
index fe649ca..b53aa39 100644
--- a/dudley/src/Assemble_PDE_System2_2D.cpp
+++ b/dudley/src/Assemble_PDE_System2_2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -44,9 +47,9 @@
 /************************************************************************************/
 
 void Dudley_Assemble_PDE_System2_2D(Dudley_Assemble_Parameters p, Dudley_ElementFile * elements,
-				    paso::SystemMatrix_ptr Mat, escriptDataC * F,
-				    escriptDataC * A, escriptDataC * B, escriptDataC * C, escriptDataC * D,
-				    escriptDataC * X, escriptDataC * Y)
+				    paso::SystemMatrix_ptr Mat, escript::Data* F,
+				    const escript::Data* A, const escript::Data* B, const escript::Data* C, const escript::Data* D,
+				    const escript::Data* X, const escript::Data* Y)
 {
 
 #define DIM 2
diff --git a/dudley/src/Assemble_PDE_System2_3D.cpp b/dudley/src/Assemble_PDE_System2_3D.cpp
index 5de1f1b..87c9c63 100644
--- a/dudley/src/Assemble_PDE_System2_3D.cpp
+++ b/dudley/src/Assemble_PDE_System2_3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -44,9 +47,9 @@
 /************************************************************************************/
 
 void Dudley_Assemble_PDE_System2_3D(Dudley_Assemble_Parameters p, Dudley_ElementFile * elements,
-				    paso::SystemMatrix_ptr Mat, escriptDataC * F,
-				    escriptDataC * A, escriptDataC * B, escriptDataC * C, escriptDataC * D,
-				    escriptDataC * X, escriptDataC * Y)
+				    paso::SystemMatrix_ptr Mat, escript::Data* F,
+				    const escript::Data* A, const escript::Data* B, const escript::Data* C, const escript::Data* D,
+				    const escript::Data* X, const escript::Data* Y)
 {
 
 #define DIM 3
diff --git a/dudley/src/Assemble_addToSystemMatrix.cpp b/dudley/src/Assemble_addToSystemMatrix.cpp
index 26e7899..f8d8f83 100644
--- a/dudley/src/Assemble_addToSystemMatrix.cpp
+++ b/dudley/src/Assemble_addToSystemMatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -29,6 +29,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Assemble_getAssembleParameters.cpp b/dudley/src/Assemble_getAssembleParameters.cpp
index 015b741..ba4b35f 100644
--- a/dudley/src/Assemble_getAssembleParameters.cpp
+++ b/dudley/src/Assemble_getAssembleParameters.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,13 +20,16 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "ShapeTable.h"
 
 /************************************************************************************/
 
 void Dudley_Assemble_getAssembleParameters(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, paso::SystemMatrix_ptr S,
-				    escriptDataC * F, bool reducedIntegrationOrder, Dudley_Assemble_Parameters * parm)
+				    const escript::Data* F, bool reducedIntegrationOrder, Dudley_Assemble_Parameters * parm)
 {
     Dudley_resetError();
     parm->shapeFns = NULL;
diff --git a/dudley/src/Assemble_getSize.cpp b/dudley/src/Assemble_getSize.cpp
index 3768014..cd2913b 100644
--- a/dudley/src/Assemble_getSize.cpp
+++ b/dudley/src/Assemble_getSize.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -30,7 +33,7 @@
 #endif
 
 /************************************************************************************/
-void Dudley_Assemble_getSize(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escriptDataC * element_size)
+void Dudley_Assemble_getSize(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escript::Data* element_size)
 {
 
     double *local_X = NULL, *element_size_array;
diff --git a/dudley/src/Assemble_gradient.cpp b/dudley/src/Assemble_gradient.cpp
index f89fa08..689cf66 100644
--- a/dudley/src/Assemble_gradient.cpp
+++ b/dudley/src/Assemble_gradient.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,10 @@
 
 /************************************************************************************/
 
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -30,7 +34,7 @@
 /* Unless the loops in here get complicated again this file should be compiled for loop unrolling */
 
 void Dudley_Assemble_gradient(Dudley_NodeFile * nodes, Dudley_ElementFile * elements,
-			      escriptDataC * grad_data, escriptDataC * data)
+			      escript::Data* grad_data, const escript::Data* data)
 {
     size_t localGradSize = 0;
     register dim_t e, q, l, s, n;
diff --git a/dudley/src/Assemble_integrate.cpp b/dudley/src/Assemble_integrate.cpp
index ced80ac..6701b28 100644
--- a/dudley/src/Assemble_integrate.cpp
+++ b/dudley/src/Assemble_integrate.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -28,7 +31,7 @@
 
 /************************************************************************************/
 
-void Dudley_Assemble_integrate(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escriptDataC * data, double *out)
+void Dudley_Assemble_integrate(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, const escript::Data* data, double *out)
 {
 /*    type_t data_type=getFunctionSpaceType(data);*/
     dim_t numQuadTotal;
diff --git a/dudley/src/Assemble_interpolate.cpp b/dudley/src/Assemble_interpolate.cpp
index 0c775b4..7c39bfa 100644
--- a/dudley/src/Assemble_interpolate.cpp
+++ b/dudley/src/Assemble_interpolate.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -30,8 +33,8 @@
 
 /************************************************************************************/
 
-void Dudley_Assemble_interpolate(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escriptDataC * data,
-				 escriptDataC * interpolated_data)
+void Dudley_Assemble_interpolate(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, const escript::Data* data,
+				 escript::Data* interpolated_data)
 {
     __const double *data_array;
     double *local_data = NULL;
diff --git a/dudley/src/Assemble_jacobeans.cpp b/dudley/src/Assemble_jacobeans.cpp
index a63e077..e1026d3 100644
--- a/dudley/src/Assemble_jacobeans.cpp
+++ b/dudley/src/Assemble_jacobeans.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
diff --git a/dudley/src/Assemble_setNormal.cpp b/dudley/src/Assemble_setNormal.cpp
index de685c4..6fc8004 100644
--- a/dudley/src/Assemble_setNormal.cpp
+++ b/dudley/src/Assemble_setNormal.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 #ifdef _OPENMP
@@ -30,7 +33,7 @@
 
 /************************************************************************************/
 
-void Dudley_Assemble_setNormal(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escriptDataC * normal)
+void Dudley_Assemble_setNormal(Dudley_NodeFile * nodes, Dudley_ElementFile * elements, escript::Data* normal)
 {
     double *local_X = NULL, *dVdv = NULL, *normal_array;
     index_t sign;
diff --git a/dudley/src/CPPAdapter/DudleyAdapterException.cpp b/dudley/src/CPPAdapter/DudleyAdapterException.cpp
index 8584d1b..e0f6880 100644
--- a/dudley/src/CPPAdapter/DudleyAdapterException.cpp
+++ b/dudley/src/CPPAdapter/DudleyAdapterException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/CPPAdapter/DudleyAdapterException.h b/dudley/src/CPPAdapter/DudleyAdapterException.h
index 6b1e40c..4c79777 100644
--- a/dudley/src/CPPAdapter/DudleyAdapterException.h
+++ b/dudley/src/CPPAdapter/DudleyAdapterException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/CPPAdapter/DudleyError.cpp b/dudley/src/CPPAdapter/DudleyError.cpp
index 419329a..f91fcf1 100644
--- a/dudley/src/CPPAdapter/DudleyError.cpp
+++ b/dudley/src/CPPAdapter/DudleyError.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/CPPAdapter/DudleyError.h b/dudley/src/CPPAdapter/DudleyError.h
index ff3b6cf..5816ca6 100644
--- a/dudley/src/CPPAdapter/DudleyError.h
+++ b/dudley/src/CPPAdapter/DudleyError.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/CPPAdapter/MeshAdapter.cpp b/dudley/src/CPPAdapter/MeshAdapter.cpp
index b756b6d..3d858dd 100644
--- a/dudley/src/CPPAdapter/MeshAdapter.cpp
+++ b/dudley/src/CPPAdapter/MeshAdapter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "MeshAdapter.h"
 #include "escript/Data.h"
@@ -694,28 +696,16 @@ void MeshAdapter::addPDEToSystem(
    {
 	throw DudleyAdapterException("Dudley only accepts Paso system matrices");
    }
-   escriptDataC _rhs=rhs.getDataC();
-   escriptDataC _A =A.getDataC();
-   escriptDataC _B=B.getDataC();
-   escriptDataC _C=C.getDataC();
-   escriptDataC _D=D.getDataC();
-   escriptDataC _X=X.getDataC();
-   escriptDataC _Y=Y.getDataC();
-   escriptDataC _d=d.getDataC();
-   escriptDataC _y=y.getDataC();
-   escriptDataC _d_dirac=d_dirac.getDataC();
-   escriptDataC _y_dirac=y_dirac.getDataC();
-
 
    Dudley_Mesh* mesh=m_dudleyMesh.get();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements,smat->getPaso_SystemMatrix(), &_rhs, &_A, &_B, &_C, &_D, &_X, &_Y );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements,smat->getPaso_SystemMatrix(), &rhs, &A, &B, &C, &D, &X, &Y );
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->FaceElements, smat->getPaso_SystemMatrix(), &_rhs, 0, 0, 0, &_d, 0, &_y );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->FaceElements, smat->getPaso_SystemMatrix(), &rhs, 0, 0, 0, &d, 0, &y );
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Points, smat->getPaso_SystemMatrix(), &_rhs, 0, 0, 0, &_d_dirac, 0, &_y_dirac );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Points, smat->getPaso_SystemMatrix(), &rhs, 0, 0, 0, &d_dirac, 0, &y_dirac );
    checkDudleyError();
 }
 
@@ -726,20 +716,15 @@ void  MeshAdapter::addPDEToLumpedSystem(
                                         const escript::Data& d_dirac,
 					const bool useHRZ) const
 {
-   escriptDataC _mat=mat.getDataC();
-   escriptDataC _D=D.getDataC();
-   escriptDataC _d=d.getDataC();
-   escriptDataC _d_dirac=d_dirac.getDataC();
-
    Dudley_Mesh* mesh=m_dudleyMesh.get();
 
-   Dudley_Assemble_LumpedSystem(mesh->Nodes,mesh->Elements,&_mat, &_D, useHRZ);
+   Dudley_Assemble_LumpedSystem(mesh->Nodes,mesh->Elements,&mat, &D, useHRZ);
    checkDudleyError();
    
-   Dudley_Assemble_LumpedSystem(mesh->Nodes,mesh->FaceElements,&_mat, &_d, useHRZ);
+   Dudley_Assemble_LumpedSystem(mesh->Nodes,mesh->FaceElements,&mat, &d, useHRZ);
    checkDudleyError();
 
-   Dudley_Assemble_LumpedSystem(mesh->Nodes,mesh->FaceElements,&_mat, &_d_dirac, useHRZ);
+   Dudley_Assemble_LumpedSystem(mesh->Nodes,mesh->FaceElements,&mat, &d_dirac, useHRZ);
    checkDudleyError();
 
 }
@@ -756,19 +741,13 @@ void MeshAdapter::addPDEToRHS( escript::Data& rhs, const  escript::Data& X,const
    }
    Dudley_Mesh* mesh=m_dudleyMesh.get();
 
-   escriptDataC _rhs=rhs.getDataC();
-   escriptDataC _X=X.getDataC();
-   escriptDataC _Y=Y.getDataC();
-   escriptDataC _y=y.getDataC();
-   escriptDataC _y_dirac=y_dirac.getDataC();
-
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements, paso::SystemMatrix_ptr(), &_rhs, 0, 0, 0, 0, &_X, &_Y);
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements, paso::SystemMatrix_ptr(), &rhs, 0, 0, 0, 0, &X, &Y);
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->FaceElements, paso::SystemMatrix_ptr(), &_rhs, 0, 0, 0, 0, 0, &_y );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->FaceElements, paso::SystemMatrix_ptr(), &rhs, 0, 0, 0, 0, 0, &y );
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Points, paso::SystemMatrix_ptr(), &_rhs, 0, 0, 0, 0, 0, &_y_dirac );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Points, paso::SystemMatrix_ptr(), &rhs, 0, 0, 0, 0, 0, &y_dirac );
    checkDudleyError();
 }
 //
@@ -797,32 +776,20 @@ void MeshAdapter::addPDEToTransportProblem(
    }
    DataTypes::ShapeType shape;
    source.expand();
-   escriptDataC _source=source.getDataC();
-   escriptDataC _M=M.getDataC();
-   escriptDataC _A=A.getDataC();
-   escriptDataC _B=B.getDataC();
-   escriptDataC _C=C.getDataC();
-   escriptDataC _D=D.getDataC();
-   escriptDataC _X=X.getDataC();
-   escriptDataC _Y=Y.getDataC();
-   escriptDataC _d=d.getDataC();
-   escriptDataC _y=y.getDataC();
-   escriptDataC _d_dirac=d_dirac.getDataC();
-   escriptDataC _y_dirac=y_dirac.getDataC();
 
    Dudley_Mesh* mesh=m_dudleyMesh.get();
    paso::TransportProblem_ptr _tp(tpa->getPaso_TransportProblem());
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements,_tp->mass_matrix, &_source, 0, 0, 0, &_M, 0, 0 );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements,_tp->mass_matrix, &source, 0, 0, 0, &M, 0, 0 );
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements,_tp->transport_matrix, &_source, &_A, &_B, &_C, &_D, &_X, &_Y );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Elements,_tp->transport_matrix, &source, &A, &B, &C, &D, &X, &Y );
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->FaceElements, _tp->transport_matrix, &_source, 0, 0, 0, &_d, 0, &_y );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->FaceElements, _tp->transport_matrix, &source, 0, 0, 0, &d, 0, &y );
    checkDudleyError();
 
-   Dudley_Assemble_PDE(mesh->Nodes,mesh->Points, _tp->transport_matrix, &_source, 0, 0, 0, &_d_dirac, 0, &_y_dirac );
+   Dudley_Assemble_PDE(mesh->Nodes,mesh->Points, _tp->transport_matrix, &source, 0, 0, 0, &d_dirac, 0, &y_dirac );
    checkDudleyError();
 }
 
@@ -839,8 +806,6 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       throw DudleyAdapterException("Error - Illegal domain of interpolation target.");
 
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC _target=target.getDataC();
-   escriptDataC _in=in.getDataC();
    switch(in.getFunctionSpace().getTypeCode()) {
    case(Nodes):
       switch(target.getFunctionSpace().getTypeCode()) {
@@ -848,18 +813,18 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       case(ReducedNodes):
       case(DegreesOfFreedom):
       case(ReducedDegreesOfFreedom):
-      Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in);
+      Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&in);
       break;
       case(Elements):
       case(ReducedElements):
-      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&_in,&_target);
+      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&in,&target);
       break;
       case(FaceElements):
       case(ReducedFaceElements):
-      Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&_in,&_target);
+      Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&in,&target);
       break;
       case(Points):
-      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&_in,&_target);
+      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&in,&target);
       break;
       default:
          stringstream temp;
@@ -874,18 +839,18 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       case(ReducedNodes):
       case(DegreesOfFreedom):
       case(ReducedDegreesOfFreedom):
-      Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in);
+      Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&in);
       break;
       case(Elements):
       case(ReducedElements):
-      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&_in,&_target);
+      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&in,&target);
       break;
       case(FaceElements):
       case(ReducedFaceElements):
-      Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&_in,&_target);
+      Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&in,&target);
       break;
       case(Points):
-      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&_in,&_target);
+      Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&in,&target);
       break;
       default:
          stringstream temp;
@@ -896,39 +861,39 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       break;
    case(Elements):
       if (target.getFunctionSpace().getTypeCode()==Elements) {
-         Dudley_Assemble_CopyElementData(mesh->Elements,&_target,&_in);
+         Dudley_Assemble_CopyElementData(mesh->Elements,&target,&in);
       } else if (target.getFunctionSpace().getTypeCode()==ReducedElements) {
-         Dudley_Assemble_AverageElementData(mesh->Elements,&_target,&_in);
+         Dudley_Assemble_AverageElementData(mesh->Elements,&target,&in);
       } else {
          throw DudleyAdapterException("Error - No interpolation with data on elements possible.");
       }
       break;
    case(ReducedElements):
       if (target.getFunctionSpace().getTypeCode()==ReducedElements) {
-         Dudley_Assemble_CopyElementData(mesh->Elements,&_target,&_in);
+         Dudley_Assemble_CopyElementData(mesh->Elements,&target,&in);
       } else {
          throw DudleyAdapterException("Error - No interpolation with data on elements with reduced integration order possible.");
       }
       break;
    case(FaceElements):
       if (target.getFunctionSpace().getTypeCode()==FaceElements) {
-         Dudley_Assemble_CopyElementData(mesh->FaceElements,&_target,&_in);
+         Dudley_Assemble_CopyElementData(mesh->FaceElements,&target,&in);
       } else if (target.getFunctionSpace().getTypeCode()==ReducedFaceElements) {
-         Dudley_Assemble_AverageElementData(mesh->FaceElements,&_target,&_in);
+         Dudley_Assemble_AverageElementData(mesh->FaceElements,&target,&in);
       } else {
          throw DudleyAdapterException("Error - No interpolation with data on face elements possible.");
       }
       break;
    case(ReducedFaceElements):
       if (target.getFunctionSpace().getTypeCode()==ReducedFaceElements) {
-         Dudley_Assemble_CopyElementData(mesh->FaceElements,&_target,&_in);
+         Dudley_Assemble_CopyElementData(mesh->FaceElements,&target,&in);
       } else {
          throw DudleyAdapterException("Error - No interpolation with data on face elements with reduced integration order possible.");
       }
       break;
    case(Points):
       if (target.getFunctionSpace().getTypeCode()==Points) {
-         Dudley_Assemble_CopyElementData(mesh->Points,&_target,&_in);
+         Dudley_Assemble_CopyElementData(mesh->Points,&target,&in);
       } else {
          throw DudleyAdapterException("Error - No interpolation with data on points possible.");
       }
@@ -937,7 +902,7 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       switch(target.getFunctionSpace().getTypeCode()) {
       case(ReducedDegreesOfFreedom):
       case(DegreesOfFreedom):
-      Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in);
+      Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&in);
       break;
    
       case(Nodes):
@@ -945,31 +910,28 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       if (getMPISize()>1) {
          escript::Data temp=escript::Data(in);
          temp.expand();
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in2);
+         Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&temp);
       } else {
-         Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in);
+         Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&in);
       }
       break;
       case(Elements):
       case(ReducedElements):
       if (getMPISize()>1) {
          escript::Data temp=escript::Data( in,  continuousFunction(*this) );
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&_in2,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&temp,&target);
       } else {
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&_in,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&in,&target);
       }
       break;
       case(FaceElements):
       case(ReducedFaceElements):
       if (getMPISize()>1) {
          escript::Data temp=escript::Data( in,  continuousFunction(*this) );
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&_in2,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&temp,&target);
    
       } else {
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&_in,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&in,&target);
       }
       break;
       case(Points):
@@ -977,7 +939,7 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
          //escript::Data temp=escript::Data( in,  continuousFunction(*this) );
          //escriptDataC _in2 = temp.getDataC();
       } else {
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&_in,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&in,&target);
       }
       break;
       default:
@@ -996,45 +958,41 @@ void MeshAdapter::interpolateOnDomain(escript::Data& target,const escript::Data&
       if (getMPISize()>1) {
          escript::Data temp=escript::Data(in);
          temp.expand();
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in2);
+         Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&temp);
       } else {
-         Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in);
+         Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&in);
       }
       break;
       case(DegreesOfFreedom):
       throw DudleyAdapterException("Error - Dudley does not support interpolation from reduced degrees of freedom to degrees of freedom");
       break;
       case(ReducedDegreesOfFreedom):
-      Dudley_Assemble_CopyNodalData(mesh->Nodes,&_target,&_in);
+      Dudley_Assemble_CopyNodalData(mesh->Nodes,&target,&in);
       break;
       case(Elements):
       case(ReducedElements):
       if (getMPISize()>1) {
          escript::Data temp=escript::Data( in,  reducedContinuousFunction(*this) );
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&_in2,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&temp,&target);
       } else {
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&_in,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Elements,&in,&target);
       }
       break;
       case(FaceElements):
       case(ReducedFaceElements):
       if (getMPISize()>1) {
          escript::Data temp=escript::Data( in,  reducedContinuousFunction(*this) );
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&_in2,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&temp,&target);
       } else {
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&_in,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->FaceElements,&in,&target);
       }
       break;
       case(Points):
       if (getMPISize()>1) {
          escript::Data temp=escript::Data( in,  reducedContinuousFunction(*this) );
-         escriptDataC _in2 = temp.getDataC();
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&_in2,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&temp,&target);
       } else {
-         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&_in,&_target);
+         Dudley_Assemble_interpolate(mesh->Nodes,mesh->Points,&in,&target);
       }
       break;
       default:
@@ -1064,12 +1022,10 @@ void MeshAdapter::setToX(escript::Data& arg) const
    Dudley_Mesh* mesh=m_dudleyMesh.get();
    // in case of values node coordinates we can do the job directly:
    if (arg.getFunctionSpace().getTypeCode()==Nodes) {
-      escriptDataC _arg=arg.getDataC();
-      Dudley_Assemble_NodeCoordinates(mesh->Nodes,&_arg);
+      Dudley_Assemble_NodeCoordinates(mesh->Nodes,&arg);
    } else {
       escript::Data tmp_data=Vector(0.0,continuousFunction(*this),true);
-      escriptDataC _tmp_data=tmp_data.getDataC();
-      Dudley_Assemble_NodeCoordinates(mesh->Nodes,&_tmp_data);
+      Dudley_Assemble_NodeCoordinates(mesh->Nodes,&tmp_data);
       // this is then interpolated onto arg:
       interpolateOnDomain(arg,tmp_data);
    }
@@ -1086,7 +1042,6 @@ void MeshAdapter::setToNormal(escript::Data& normal) const
    if (normalDomain!=*this) 
       throw DudleyAdapterException("Error - Illegal domain of normal locations");
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC _normal=normal.getDataC();
    switch(normal.getFunctionSpace().getTypeCode()) {
    case(Nodes):
    throw DudleyAdapterException("Error - Dudley does not support surface normal vectors for nodes");
@@ -1101,10 +1056,10 @@ void MeshAdapter::setToNormal(escript::Data& normal) const
    throw DudleyAdapterException("Error - Dudley does not support surface normal vectors for elements with reduced integration order");
    break;
    case (FaceElements):
-   Dudley_Assemble_setNormal(mesh->Nodes,mesh->FaceElements,&_normal);
+   Dudley_Assemble_setNormal(mesh->Nodes,mesh->FaceElements,&normal);
    break;
    case (ReducedFaceElements):
-   Dudley_Assemble_setNormal(mesh->Nodes,mesh->FaceElements,&_normal);
+   Dudley_Assemble_setNormal(mesh->Nodes,mesh->FaceElements,&normal);
    break;
    case(Points):
    throw DudleyAdapterException("Error - Dudley does not support surface normal vectors for point elements");
@@ -1148,44 +1103,38 @@ void MeshAdapter::setToIntegrals(vector<double>& integrals,const escript::Data&
 
    double blocktimer_start = blocktimer_time();
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC _temp;
    escript::Data temp;
-   escriptDataC _arg=arg.getDataC();
    switch(arg.getFunctionSpace().getTypeCode()) {
    case(Nodes):
    temp=escript::Data( arg, escript::function(*this) );
-   _temp=temp.getDataC();
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&_temp,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&temp,&integrals[0]);
    break;
    case(ReducedNodes):
    temp=escript::Data( arg, escript::function(*this) );
-   _temp=temp.getDataC();
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&_temp,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&temp,&integrals[0]);
    break;
    case(Elements):
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&_arg,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&arg,&integrals[0]);
    break;
    case(ReducedElements):
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&_arg,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&arg,&integrals[0]);
    break;
    case(FaceElements):
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->FaceElements,&_arg,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->FaceElements,&arg,&integrals[0]);
    break;
    case(ReducedFaceElements):
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->FaceElements,&_arg,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->FaceElements,&arg,&integrals[0]);
    break;
    case(Points):
    throw DudleyAdapterException("Error - Integral of data on points is not supported.");
    break;
    case(DegreesOfFreedom):
    temp=escript::Data( arg, escript::function(*this) );
-   _temp=temp.getDataC();
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&_temp,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&temp,&integrals[0]);
    break;
    case(ReducedDegreesOfFreedom):
    temp=escript::Data( arg, escript::function(*this) );
-   _temp=temp.getDataC();
-   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&_temp,&integrals[0]);
+   Dudley_Assemble_integrate(mesh->Nodes,mesh->Elements,&temp,&integrals[0]);
    break;
    default:
       stringstream temp;
@@ -1210,21 +1159,20 @@ void MeshAdapter::setToGradient(escript::Data& grad,const escript::Data& arg) co
       throw DudleyAdapterException("Error - Illegal domain of gradient");
 
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC _grad=grad.getDataC();
-   escriptDataC nodeDataC;
+   const escript::Data* nodeData=0;
    escript::Data temp;
    if (getMPISize()>1) {
       if( arg.getFunctionSpace().getTypeCode() == DegreesOfFreedom ) {
          temp=escript::Data( arg,  continuousFunction(*this) );
-         nodeDataC = temp.getDataC();
+         nodeData = &temp;
       } else if( arg.getFunctionSpace().getTypeCode() == ReducedDegreesOfFreedom ) {
          temp=escript::Data( arg,  reducedContinuousFunction(*this) );
-         nodeDataC = temp.getDataC();
+         nodeData = &temp;
       } else {
-         nodeDataC = arg.getDataC();
+         nodeData = &arg;
       }
    } else {
-      nodeDataC = arg.getDataC();
+      nodeData = &arg;
    }
    switch(grad.getFunctionSpace().getTypeCode()) {
    case(Nodes):
@@ -1234,16 +1182,16 @@ void MeshAdapter::setToGradient(escript::Data& grad,const escript::Data& arg) co
    throw DudleyAdapterException("Error - Gradient at reduced nodes is not supported.");
    break;
    case(Elements):
-   Dudley_Assemble_gradient(mesh->Nodes,mesh->Elements,&_grad,&nodeDataC);
+   Dudley_Assemble_gradient(mesh->Nodes,mesh->Elements,&grad, nodeData);
    break;
    case(ReducedElements):
-   Dudley_Assemble_gradient(mesh->Nodes,mesh->Elements,&_grad,&nodeDataC);
+   Dudley_Assemble_gradient(mesh->Nodes,mesh->Elements,&grad, nodeData);
    break;
    case(FaceElements):
-   Dudley_Assemble_gradient(mesh->Nodes,mesh->FaceElements,&_grad,&nodeDataC);
+   Dudley_Assemble_gradient(mesh->Nodes,mesh->FaceElements,&grad, nodeData);
    break;
    case(ReducedFaceElements):
-   Dudley_Assemble_gradient(mesh->Nodes,mesh->FaceElements,&_grad,&nodeDataC);
+   Dudley_Assemble_gradient(mesh->Nodes,mesh->FaceElements,&grad, nodeData);
    break;
    case(Points):
    throw DudleyAdapterException("Error - Gradient at points is not supported.");
@@ -1269,7 +1217,6 @@ void MeshAdapter::setToGradient(escript::Data& grad,const escript::Data& arg) co
 void MeshAdapter::setToSize(escript::Data& size) const
 {
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC tmp=size.getDataC();
    switch(size.getFunctionSpace().getTypeCode()) {
    case(Nodes):
    throw DudleyAdapterException("Error - Size of nodes is not supported.");
@@ -1278,16 +1225,16 @@ void MeshAdapter::setToSize(escript::Data& size) const
    throw DudleyAdapterException("Error - Size of reduced nodes is not supported.");
    break;
    case(Elements):
-   Dudley_Assemble_getSize(mesh->Nodes,mesh->Elements,&tmp);
+   Dudley_Assemble_getSize(mesh->Nodes,mesh->Elements,&size);
    break;
    case(ReducedElements):
-   Dudley_Assemble_getSize(mesh->Nodes,mesh->Elements,&tmp);
+   Dudley_Assemble_getSize(mesh->Nodes,mesh->Elements,&size);
    break;
    case(FaceElements):
-   Dudley_Assemble_getSize(mesh->Nodes,mesh->FaceElements,&tmp);
+   Dudley_Assemble_getSize(mesh->Nodes,mesh->FaceElements,&size);
    break;
    case(ReducedFaceElements):
-   Dudley_Assemble_getSize(mesh->Nodes,mesh->FaceElements,&tmp);
+   Dudley_Assemble_getSize(mesh->Nodes,mesh->FaceElements,&size);
    break;
    case(Points):
    throw DudleyAdapterException("Error - Size of point elements is not supported.");
@@ -1313,18 +1260,14 @@ void MeshAdapter::setToSize(escript::Data& size) const
 void MeshAdapter::setNewX(const escript::Data& new_x)
 {
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC tmp;
    const MeshAdapter& newDomain=dynamic_cast<const MeshAdapter&>(*(new_x.getFunctionSpace().getDomain()));
    if (newDomain!=*this) 
       throw DudleyAdapterException("Error - Illegal domain of new point locations");
    if ( new_x.getFunctionSpace() == continuousFunction(*this) ) {
-       tmp = new_x.getDataC();
-       Dudley_Mesh_setCoordinates(mesh,&tmp);
+       Dudley_Mesh_setCoordinates(mesh,&new_x);
    } else {
        throw DudleyAdapterException("As of version escript3.3 - SetNewX only accepts ContinuousFunction arguments please interpolate.");      
-/*       escript::Data new_x_inter=escript::Data( new_x,  continuousFunction(*this) );
-       tmp = new_x_inter.getDataC();
-       Dudley_Mesh_setCoordinates(mesh,&tmp);*/
+
    }
    checkDudleyError();
 }
@@ -1874,10 +1817,9 @@ int MeshAdapter::getTagFromSampleNo(int functionSpaceType, int sampleNo) const
 void MeshAdapter::setTags(const int functionSpaceType, const int newTag, const escript::Data& mask) const
 {
    Dudley_Mesh* mesh=m_dudleyMesh.get();
-   escriptDataC tmp=mask.getDataC();
    switch(functionSpaceType) {
    case(Nodes):
-   Dudley_NodeFile_setTags(mesh->Nodes,newTag,&tmp);
+   Dudley_NodeFile_setTags(mesh->Nodes,newTag,&mask);
    break;
    case(ReducedNodes):
    throw DudleyAdapterException("Error - ReducedNodes does not support tags");
@@ -1889,19 +1831,19 @@ void MeshAdapter::setTags(const int functionSpaceType, const int newTag, const e
    throw DudleyAdapterException("Error - ReducedDegreesOfFreedom does not support tags");
    break;
    case(Elements):
-   Dudley_ElementFile_setTags(mesh->Elements,newTag,&tmp);
+   Dudley_ElementFile_setTags(mesh->Elements,newTag,&mask);
    break;
    case(ReducedElements):
-   Dudley_ElementFile_setTags(mesh->Elements,newTag,&tmp);
+   Dudley_ElementFile_setTags(mesh->Elements,newTag,&mask);
    break;
    case(FaceElements):
-   Dudley_ElementFile_setTags(mesh->FaceElements,newTag,&tmp);
+   Dudley_ElementFile_setTags(mesh->FaceElements,newTag,&mask);
    break;
    case(ReducedFaceElements):
-   Dudley_ElementFile_setTags(mesh->FaceElements,newTag,&tmp);
+   Dudley_ElementFile_setTags(mesh->FaceElements,newTag,&mask);
    break;
    case(Points):
-   Dudley_ElementFile_setTags(mesh->Points,newTag,&tmp);
+   Dudley_ElementFile_setTags(mesh->Points,newTag,&mask);
    break;
    default:
       stringstream temp;
diff --git a/dudley/src/CPPAdapter/MeshAdapter.h b/dudley/src/CPPAdapter/MeshAdapter.h
index 40a2555..b662922 100644
--- a/dudley/src/CPPAdapter/MeshAdapter.h
+++ b/dudley/src/CPPAdapter/MeshAdapter.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -410,7 +410,7 @@ class MeshAdapter : public escript::AbstractContinuousDomain
      interpolates data given on source onto target where source and target have to be given on the same domain.
   */
   DUDLEY_DLL_API
-  virtual void interpolateOnDomain(escript::Data& target,const escript::Data& source) const;
+  virtual void interpolateOnDomain(escript::Data& target, const escript::Data& source) const;
 
 
   DUDLEY_DLL_API
@@ -656,8 +656,8 @@ class MeshAdapter : public escript::AbstractContinuousDomain
 
  private:
   void extractArgsFromDict(const boost::python::dict& arg, int& numData,
-                             char**& names, escriptDataC*& data,
-                             escriptDataC**& dataPtr) const;
+                             char**& names, escript::Data*& data,
+                             escript::Data**& dataPtr) const;
 
   //
   // pointer to the externally created dudley mesh
diff --git a/dudley/src/CPPAdapter/MeshAdapterFactory.cpp b/dudley/src/CPPAdapter/MeshAdapterFactory.cpp
index 2b82f96..df8a4be 100644
--- a/dudley/src/CPPAdapter/MeshAdapterFactory.cpp
+++ b/dudley/src/CPPAdapter/MeshAdapterFactory.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "MeshAdapterFactory.h"
 #include "DudleyError.h"
 #include "esysUtils/blocktimer.h"
diff --git a/dudley/src/CPPAdapter/MeshAdapterFactory.h b/dudley/src/CPPAdapter/MeshAdapterFactory.h
index 75f2d17..52e9ca7 100644
--- a/dudley/src/CPPAdapter/MeshAdapterFactory.h
+++ b/dudley/src/CPPAdapter/MeshAdapterFactory.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/CPPAdapter/dudleycpp.cpp b/dudley/src/CPPAdapter/dudleycpp.cpp
index 9a6442a..bfa2962 100644
--- a/dudley/src/CPPAdapter/dudleycpp.cpp
+++ b/dudley/src/CPPAdapter/dudleycpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #ifdef ESYS_MPI
 #include "esysUtils/Esys_MPI.h"
diff --git a/dudley/src/CPPAdapter/system_dep.h b/dudley/src/CPPAdapter/system_dep.h
index 1460821..0f10b97 100644
--- a/dudley/src/CPPAdapter/system_dep.h
+++ b/dudley/src/CPPAdapter/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,21 +26,6 @@
 #ifndef dudley_system_dep_h
 #define dudley_system_dep_h
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/*
- * The Intel compiler on windows has an "improved" math library compared to
- * the usual Visual C++ one. In particular it has acosh and other similar
- * functions which aren't implemented in Visual C++ math.h.
- * Note you will get a compile time error if any other header (including
- * system ones) includes math.h whilst mathimf.h has been included.
- * As a result system_dep.h must be included FIRST at all times (this
- * prevents math.h from being included).
- */
-#   include <mathimf.h>
-#else
-#   include <cmath>
-#endif
-
 #define DUDLEY_DLL_API
 
 #ifdef _WIN32
diff --git a/dudley/src/Dudley.cpp b/dudley/src/Dudley.cpp
index b9a2d4b..fa64bd8 100644
--- a/dudley/src/Dudley.cpp
+++ b/dudley/src/Dudley.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/Dudley.h b/dudley/src/Dudley.h
index 9b70d87..c48ada0 100644
--- a/dudley/src/Dudley.h
+++ b/dudley/src/Dudley.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/DudleyVersion.h b/dudley/src/DudleyVersion.h
index cc20510..c8c5ef1 100644
--- a/dudley/src/DudleyVersion.h
+++ b/dudley/src/DudleyVersion.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -17,6 +17,6 @@
 #ifndef INC_DUDLEYVERSION
 #define INC_DUDLEYVERSION
 
-char Dudley_Version[] = "$Revision: 5406 $";
+char Dudley_Version[] = "$Revision: 5593 $";
 
 #endif
diff --git a/dudley/src/ElementFile.cpp b/dudley/src/ElementFile.cpp
index 054a6f7..e5b5a9f 100644
--- a/dudley/src/ElementFile.cpp
+++ b/dudley/src/ElementFile.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include "ShapeTable.h"
 
diff --git a/dudley/src/ElementFile.h b/dudley/src/ElementFile.h
index 0404506..4bc6055 100644
--- a/dudley/src/ElementFile.h
+++ b/dudley/src/ElementFile.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -107,7 +107,7 @@ void Dudley_ElementFile_markDOFsConnectedToRange(index_t * mask, index_t offset,
 						 index_t lastDOF, index_t * dofIndex, Dudley_ElementFile * in,
 						 bool useLinear);
 
-void Dudley_ElementFile_setTags(Dudley_ElementFile *, const int, escriptDataC *);
+void Dudley_ElementFile_setTags(Dudley_ElementFile *, const int, const escript::Data *);
 Dudley_ElementFile_Jacobeans *Dudley_ElementFile_Jacobeans_alloc(void);
 void Dudley_ElementFile_Jacobeans_dealloc(Dudley_ElementFile_Jacobeans *);
 Dudley_ElementFile_Jacobeans *Dudley_ElementFile_borrowJacobeans(Dudley_ElementFile *, Dudley_NodeFile *, bool);
diff --git a/dudley/src/ElementFile_allocTable.cpp b/dudley/src/ElementFile_allocTable.cpp
index 7fa2791..4b41785 100644
--- a/dudley/src/ElementFile_allocTable.cpp
+++ b/dudley/src/ElementFile_allocTable.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include "Util.h"
 
diff --git a/dudley/src/ElementFile_copyTable.cpp b/dudley/src/ElementFile_copyTable.cpp
index 42d8e69..b3a701d 100644
--- a/dudley/src/ElementFile_copyTable.cpp
+++ b/dudley/src/ElementFile_copyTable.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,8 @@
 /* the elements offset to in->numElements+offset-1 in out will be overwritten */
 
 /************************************************************************************/
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "ElementFile.h"
 
diff --git a/dudley/src/ElementFile_createColoring.cpp b/dudley/src/ElementFile_createColoring.cpp
index 929211f..7550a06 100644
--- a/dudley/src/ElementFile_createColoring.cpp
+++ b/dudley/src/ElementFile_createColoring.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 /*                                                                                                         */
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include "Util.h"
 
diff --git a/dudley/src/ElementFile_distributeByRankOfDOF.cpp b/dudley/src/ElementFile_distributeByRankOfDOF.cpp
index 93d8a06..46b3263 100644
--- a/dudley/src/ElementFile_distributeByRankOfDOF.cpp
+++ b/dudley/src/ElementFile_distributeByRankOfDOF.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -19,6 +19,10 @@
 /*   Dudley: ElementFile: this will redistribute the Elements including overlap by */
 
 /************************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #ifdef _OPENMP
 #include <omp.h>
diff --git a/dudley/src/ElementFile_gather.cpp b/dudley/src/ElementFile_gather.cpp
index 0f82448..b2b7412 100644
--- a/dudley/src/ElementFile_gather.cpp
+++ b/dudley/src/ElementFile_gather.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/ElementFile_jacobeans.cpp b/dudley/src/ElementFile_jacobeans.cpp
index df85ab2..b5e754c 100644
--- a/dudley/src/ElementFile_jacobeans.cpp
+++ b/dudley/src/ElementFile_jacobeans.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include "Assemble.h"
 #ifdef _OPENMP
diff --git a/dudley/src/ElementFile_markNodes.cpp b/dudley/src/ElementFile_markNodes.cpp
index fe692dd..b67433a 100644
--- a/dudley/src/ElementFile_markNodes.cpp
+++ b/dudley/src/ElementFile_markNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/ElementFile_optimizeOrdering.cpp b/dudley/src/ElementFile_optimizeOrdering.cpp
index 923ffb6..8aa8b4b 100644
--- a/dudley/src/ElementFile_optimizeOrdering.cpp
+++ b/dudley/src/ElementFile_optimizeOrdering.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 /*                                                                                                         */
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Util.h"
 #include "ElementFile.h"
 
diff --git a/dudley/src/ElementFile_relableNodes.cpp b/dudley/src/ElementFile_relableNodes.cpp
index 19f09fb..1ef5587 100644
--- a/dudley/src/ElementFile_relableNodes.cpp
+++ b/dudley/src/ElementFile_relableNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/ElementFile_scatter.cpp b/dudley/src/ElementFile_scatter.cpp
index 3229088..4a1eec8 100644
--- a/dudley/src/ElementFile_scatter.cpp
+++ b/dudley/src/ElementFile_scatter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 *                                                                                            
 ************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/ElementFile_setCoordinates.cpp b/dudley/src/ElementFile_setCoordinates.cpp
index 1d86474..e13716b 100644
--- a/dudley/src/ElementFile_setCoordinates.cpp
+++ b/dudley/src/ElementFile_setCoordinates.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,11 +20,14 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 
 /************************************************************************************/
 
-void Dudley_ElementFile_setCoordinates(Dudley_ElementFile * self, escriptDataC * newX)
+void Dudley_ElementFile_setCoordinates(Dudley_ElementFile * self, escript::Data* newX)
 {
     /* self->volume_is_valid=FALSE;   
        self->DSDV_is_valid=FALSE;    
@@ -32,6 +35,3 @@ void Dudley_ElementFile_setCoordinates(Dudley_ElementFile * self, escriptDataC *
        self->X_is_valid=FALSE;          */
 }
 
-/*
-* $Log$
-*/
diff --git a/dudley/src/ElementFile_setNodeRange.cpp b/dudley/src/ElementFile_setNodeRange.cpp
index 7344438..b95f45e 100644
--- a/dudley/src/ElementFile_setNodeRange.cpp
+++ b/dudley/src/ElementFile_setNodeRange.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 /*                                                                                            */
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include "Util.h"
 
diff --git a/dudley/src/ElementFile_setTags.cpp b/dudley/src/ElementFile_setTags.cpp
index d1e95db..58e2f03 100644
--- a/dudley/src/ElementFile_setTags.cpp
+++ b/dudley/src/ElementFile_setTags.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,13 +22,16 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include "Util.h"
 #include "Assemble.h"
 
 /************************************************************************************/
 
-void Dudley_ElementFile_setTags(Dudley_ElementFile * self, const int newTag, escriptDataC * mask)
+void Dudley_ElementFile_setTags(Dudley_ElementFile * self, const int newTag, const escript::Data* mask)
 {
     register dim_t n, q;
     dim_t numElements, numQuad;
diff --git a/dudley/src/ElementType.cpp b/dudley/src/ElementType.cpp
index 6d89586..04b1d6c 100644
--- a/dudley/src/ElementType.cpp
+++ b/dudley/src/ElementType.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2010-2014 by University of Queensland
+* Copyright (c) 2010-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/ElementType.h b/dudley/src/ElementType.h
index 208a51c..08be24b 100644
--- a/dudley/src/ElementType.h
+++ b/dudley/src/ElementType.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2010-2014 by University of Queensland
+* Copyright (c) 2010-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/IndexList.cpp b/dudley/src/IndexList.cpp
index 753ab7a..74e73fd 100644
--- a/dudley/src/IndexList.cpp
+++ b/dudley/src/IndexList.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "IndexList.h"
 
 /* Translate from distributed/local array indices to global indices */
diff --git a/dudley/src/IndexList.h b/dudley/src/IndexList.h
index 654c4f7..b483f32 100644
--- a/dudley/src/IndexList.h
+++ b/dudley/src/IndexList.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/Mesh.cpp b/dudley/src/Mesh.cpp
index d15301e..5ed39f4 100644
--- a/dudley/src/Mesh.cpp
+++ b/dudley/src/Mesh.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -19,6 +19,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh.h b/dudley/src/Mesh.h
index e186779..9e2699d 100644
--- a/dudley/src/Mesh.h
+++ b/dudley/src/Mesh.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -128,7 +128,7 @@ Dudley_Mesh *Dudley_Mesh_read(char *, index_t, index_t, bool);
 Dudley_Mesh *Dudley_Mesh_readGmsh(char *, index_t, index_t, index_t, bool, bool);
 void Dudley_Mesh_setOrders(Dudley_Mesh * in);
 
-void Dudley_Mesh_setCoordinates(Dudley_Mesh *, escriptDataC *);
+void Dudley_Mesh_setCoordinates(Dudley_Mesh *, const escript::Data*);
 void Dudley_Mesh_setElements(Dudley_Mesh * self, Dudley_ElementFile * elements);
 void Dudley_Mesh_setFaceElements(Dudley_Mesh * self, Dudley_ElementFile * elements);
 void Dudley_Mesh_setPoints(Dudley_Mesh * self, Dudley_ElementFile * elements);
diff --git a/dudley/src/Mesh_createNodeFileMappings.cpp b/dudley/src/Mesh_createNodeFileMappings.cpp
index 2e48555..c960117 100644
--- a/dudley/src/Mesh_createNodeFileMappings.cpp
+++ b/dudley/src/Mesh_createNodeFileMappings.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #define UNUSED -1
 
diff --git a/dudley/src/Mesh_distributeByRankOfDOF.cpp b/dudley/src/Mesh_distributeByRankOfDOF.cpp
index b89c6c6..f774c60 100644
--- a/dudley/src/Mesh_distributeByRankOfDOF.cpp
+++ b/dudley/src/Mesh_distributeByRankOfDOF.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh_findMatchingFaces.cpp b/dudley/src/Mesh_findMatchingFaces.cpp
index a1e834a..b4dbe36 100644
--- a/dudley/src/Mesh_findMatchingFaces.cpp
+++ b/dudley/src/Mesh_findMatchingFaces.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Util.h"
 #include "Mesh.h"
 
diff --git a/dudley/src/Mesh_getPattern.cpp b/dudley/src/Mesh_getPattern.cpp
index acf190b..2a3c028 100644
--- a/dudley/src/Mesh_getPattern.cpp
+++ b/dudley/src/Mesh_getPattern.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #include "IndexList.h"
 #include <boost/scoped_array.hpp>
diff --git a/dudley/src/Mesh_markNodes.cpp b/dudley/src/Mesh_markNodes.cpp
index 312a49c..454ffe5 100644
--- a/dudley/src/Mesh_markNodes.cpp
+++ b/dudley/src/Mesh_markNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh_optimizeDOFDistribution.cpp b/dudley/src/Mesh_optimizeDOFDistribution.cpp
index b8297f9..5d5ae27 100644
--- a/dudley/src/Mesh_optimizeDOFDistribution.cpp
+++ b/dudley/src/Mesh_optimizeDOFDistribution.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #include "IndexList.h"
 #ifdef _OPENMP
@@ -29,6 +32,9 @@
 #endif
 #ifdef USE_PARMETIS
 #include "parmetis.h"
+#ifndef REALTYPEWIDTH
+typedef float real_t;
+#endif
 #endif
 
 #include <boost/scoped_array.hpp>
@@ -48,240 +54,230 @@ int Check_Inputs_For_Parmetis(dim_t mpiSize, dim_t rank, dim_t * distribution, M
 
     if (rank == 0)
     {
-	for (i = 0; i < mpiSize; i++)
-	{
-	    len = distribution[i + 1] - distribution[i];
-	    if (len == 0)
-	    {
-		ret_val = 0;
-		break;
-	    }
-	}
+        for (i = 0; i < mpiSize; i++)
+        {
+            len = distribution[i + 1] - distribution[i];
+            if (len == 0)
+            {
+                ret_val = 0;
+                break;
+            }
+        }
     }
     MPI_Bcast(&ret_val, 1, MPI_INTEGER, 0, *comm);
     if (ret_val == 0)
-	printf("INFO: Parmetis is not used since some nodes have no vertex!\n");
+        printf("INFO: Parmetis is not used since some nodes have no vertex!\n");
     return ret_val;
 }
 #endif
 
-/************************************************************************************/
+/*****************************************************************************/
 
-void Dudley_Mesh_optimizeDOFDistribution(Dudley_Mesh * in, dim_t * distribution)
+void Dudley_Mesh_optimizeDOFDistribution(Dudley_Mesh* in, dim_t* distribution)
 {
+    if (in == NULL || in->Nodes == NULL)
+        return;
 
-    dim_t dim, i, j, k, myNumVertices, p, mpiSize, len, globalNumVertices, *partition_count = NULL, *new_distribution =
-	NULL, *loc_partition_count = NULL;
-    bool *setNewDOFId = NULL;
-    index_t myFirstVertex, myLastVertex, firstVertex, lastVertex, *newGlobalDOFID = NULL;
-    size_t mpiSize_size;
-    index_t *partition = NULL;
-    paso::Pattern_ptr pattern;
-    Esys_MPI_rank myRank, current_rank, rank;
-    float *xyz = NULL;
+    dim_t i, k;
+    Esys_MPI_rank rank;
     int c;
 
-#ifdef ESYS_MPI
-    Esys_MPI_rank dest, source;
-    MPI_Status status;
-#endif
+    const Esys_MPI_rank myRank = in->MPIInfo->rank;
+    dim_t mpiSize = in->MPIInfo->size;
 
-    if (in == NULL)
-	return;
-    if (in->Nodes == NULL)
-	return;
+    // first step is to distribute the elements according to a global X of DOF
 
-    myRank = in->MPIInfo->rank;
-    mpiSize = in->MPIInfo->size;
-    mpiSize_size = mpiSize * sizeof(dim_t);
-    dim = in->Nodes->numDim;
-    /* first step is to distribute the elements according to a global X of DOF */
+    index_t myFirstVertex = distribution[myRank];
+    index_t myLastVertex = distribution[myRank + 1];
+    dim_t myNumVertices = myLastVertex - myFirstVertex;
+    dim_t globalNumVertices = distribution[mpiSize];
+    dim_t len = 0;
+    for (dim_t p = 0; p < mpiSize; ++p)
+        len = MAX(len, distribution[p + 1] - distribution[p]);
 
-    myFirstVertex = distribution[myRank];
-    myLastVertex = distribution[myRank + 1];
-    myNumVertices = myLastVertex - myFirstVertex;
-    globalNumVertices = distribution[mpiSize];
-    len = 0;
-    for (p = 0; p < mpiSize; ++p)
-	len = MAX(len, distribution[p + 1] - distribution[p]);
-    partition = new  index_t[len];	/* len is used for the sending around of partition later on */
-    xyz = new  float[myNumVertices * dim];
-    partition_count = new  dim_t[mpiSize + 1];
-    new_distribution = new  dim_t[mpiSize + 1];
-    newGlobalDOFID = new  index_t[len];
-    setNewDOFId = new  bool[in->Nodes->numNodes];
-    if (!
-	(Dudley_checkPtr(partition) || Dudley_checkPtr(xyz) || Dudley_checkPtr(partition_count)
-	 || Dudley_checkPtr(partition_count) || Dudley_checkPtr(newGlobalDOFID) || Dudley_checkPtr(setNewDOFId)))
-    {
-	dim_t *recvbuf = new  dim_t[mpiSize * mpiSize];
+    index_t* partition = new index_t[len];
+    dim_t* partition_count = new dim_t[mpiSize + 1];
+    dim_t* new_distribution = new dim_t[mpiSize + 1];
+    index_t* newGlobalDOFID = new index_t[len];
+    bool* setNewDOFId = new bool[in->Nodes->numNodes];
+    dim_t* recvbuf = new dim_t[mpiSize * mpiSize];
 
-	/* set the coordinates: */
-	/* it is assumed that at least one node on this processor provides a coordinate */
-#pragma omp parallel for private(i,j,k)
-	for (i = 0; i < in->Nodes->numNodes; ++i)
-	{
-	    k = in->Nodes->globalDegreesOfFreedom[i] - myFirstVertex;
-	    if ((k >= 0) && (k < myNumVertices))
-	    {
-		for (j = 0; j < dim; ++j)
-		    xyz[k * dim + j] = (float)(in->Nodes->Coordinates[INDEX2(j, i, dim)]);
-	    }
-	}
+#ifdef USE_PARMETIS
+    dim_t dim = in->Nodes->numDim;
+    real_t* xyz = new real_t[myNumVertices * dim];
 
-	boost::scoped_array<IndexList> index_list(new IndexList[myNumVertices]);
-	/* ksteube CSR of DOF IDs */
-	/* create the adjacency structure xadj and adjncy */
-	{
-#pragma omp parallel
-	    {
-		/* ksteube build CSR format */
-		/*  insert contributions from element matrices into columns index index_list: */
-		Dudley_IndexList_insertElementsWithRowRangeNoMainDiagonal(index_list.get(),
-                myFirstVertex, myLastVertex, in->Elements,
-                in->Nodes->globalDegreesOfFreedom,
-                in->Nodes->globalDegreesOfFreedom);
-		Dudley_IndexList_insertElementsWithRowRangeNoMainDiagonal(index_list.get(),
-                myFirstVertex, myLastVertex, in->FaceElements,
-                in->Nodes->globalDegreesOfFreedom,
-                in->Nodes->globalDegreesOfFreedom);
-		Dudley_IndexList_insertElementsWithRowRangeNoMainDiagonal(index_list.get(),
-                myFirstVertex, myLastVertex, in->Points,
-                in->Nodes->globalDegreesOfFreedom,
-                in->Nodes->globalDegreesOfFreedom);
-	    }
+    /* set the coordinates: */
+    /* it is assumed that at least one node on this processor provides a coordinate */
+#pragma omp parallel for private(i,k)
+    for (i = 0; i < in->Nodes->numNodes; ++i)
+    {
+        k = in->Nodes->globalDegreesOfFreedom[i] - myFirstVertex;
+        if ((k >= 0) && (k < myNumVertices))
+        {
+            for (dim_t j = 0; j < dim; ++j)
+                xyz[k * dim + j] = (real_t)(in->Nodes->Coordinates[INDEX2(j, i, dim)]);
+        }
+    }
+#endif // USE_PARMETIS
 
-	    /* create the local matrix pattern */
-	    pattern = paso::Pattern::fromIndexListArray(0, myNumVertices, index_list.get(), 0, globalNumVertices, 0);
+    boost::scoped_array<IndexList> index_list(new IndexList[myNumVertices]);
+    /* ksteube CSR of DOF IDs */
+    /* create the adjacency structure xadj and adjncy */
+    {
+#pragma omp parallel
+        {
+            /* ksteube build CSR format */
+            /*  insert contributions from element matrices into columns index index_list: */
+            Dudley_IndexList_insertElementsWithRowRangeNoMainDiagonal(index_list.get(),
+            myFirstVertex, myLastVertex, in->Elements,
+            in->Nodes->globalDegreesOfFreedom,
+            in->Nodes->globalDegreesOfFreedom);
+            Dudley_IndexList_insertElementsWithRowRangeNoMainDiagonal(index_list.get(),
+            myFirstVertex, myLastVertex, in->FaceElements,
+            in->Nodes->globalDegreesOfFreedom,
+            in->Nodes->globalDegreesOfFreedom);
+            Dudley_IndexList_insertElementsWithRowRangeNoMainDiagonal(index_list.get(),
+            myFirstVertex, myLastVertex, in->Points,
+            in->Nodes->globalDegreesOfFreedom,
+            in->Nodes->globalDegreesOfFreedom);
+        }
 
-	    if (Dudley_noError())
-	    {
+        /* create the local matrix pattern */
+        paso::Pattern_ptr pattern = paso::Pattern::fromIndexListArray(0,
+                myNumVertices, index_list.get(), 0, globalNumVertices, 0);
 
+        if (Dudley_noError())
+        {
 #ifdef USE_PARMETIS
 
-		if (mpiSize > 1 && Check_Inputs_For_Parmetis(mpiSize, myRank, distribution, &(in->MPIInfo->comm)) > 0)
-		{
-		    int i;
-		    int wgtflag = 0;
-		    int numflag = 0;	/* pattern->ptr is C style: starting from 0 instead of 1 */
-		    int ncon = 1;
-		    int edgecut;
-		    int options[2];
-		    float *tpwgts = new  float[ncon * mpiSize];
-		    float *ubvec = new  float[ncon];
-		    for (i = 0; i < ncon * mpiSize; i++)
-			tpwgts[i] = 1.0 / (float)mpiSize;
-		    for (i = 0; i < ncon; i++)
-			ubvec[i] = 1.05;
-		    options[0] = 3;
-		    options[1] = 15;
-		    ParMETIS_V3_PartGeomKway(distribution, pattern->ptr, pattern->index, NULL, NULL, &wgtflag, &numflag, &dim, xyz, &ncon, &mpiSize, tpwgts, ubvec, options, &edgecut, partition,	/* new CPU ownership of elements */
-					     &(in->MPIInfo->comm));
-		    /* printf("ParMETIS number of edges cut by partitioning per processor: %d\n", edgecut/MAX(in->MPIInfo->size,1)); */
-		    delete[] ubvec;
-		    delete[] tpwgts;
-		}
-		else
-		{
-		    for (i = 0; i < myNumVertices; ++i)
-			partition[i] = 0;	/* CPU 0 owns it */
-		}
+            if (mpiSize > 1 && Check_Inputs_For_Parmetis(mpiSize, myRank, distribution, &(in->MPIInfo->comm)) > 0)
+            {
+                int i;
+                int wgtflag = 0;
+                int numflag = 0;    /* pattern->ptr is C style: starting from 0 instead of 1 */
+                int ncon = 1;
+                int edgecut;
+                int options[3];
+                real_t *tpwgts = new real_t[ncon * mpiSize];
+                real_t *ubvec = new real_t[ncon];
+                for (i = 0; i < ncon * mpiSize; i++)
+                    tpwgts[i] = 1.0 / (real_t)mpiSize;
+                for (i = 0; i < ncon; i++)
+                    ubvec[i] = 1.05;
+                options[0] = 1;
+                options[1] = 15;
+                options[2] = 0;
+                ParMETIS_V3_PartGeomKway(distribution, pattern->ptr,
+                        pattern->index, NULL, NULL, &wgtflag, &numflag, &dim,
+                        xyz, &ncon, &mpiSize, tpwgts, ubvec, options, &edgecut,
+                        partition, /* new CPU ownership of elements */
+                        &in->MPIInfo->comm);
+                //printf("ParMETIS number of edges cut by partitioning per processor: %d\n", edgecut/MAX(in->MPIInfo->size,1));
+                delete[] xyz;
+                delete[] ubvec;
+                delete[] tpwgts;
+            }
+            else
+            {
+                for (i = 0; i < myNumVertices; ++i)
+                    partition[i] = 0;       /* CPU 0 owns it */
+            }
 #else
-		for (i = 0; i < myNumVertices; ++i)
-		    partition[i] = myRank;	/* CPU 0 owns it */
-#endif
+            for (i = 0; i < myNumVertices; ++i)
+                partition[i] = myRank;      /* CPU 0 owns it */
+#endif // USE_PARMETIS
 
-	    }
+        }
 
-	    /* create a new distribution and labelling of the DOF */
-	    memset(new_distribution, 0, mpiSize_size);
-#pragma omp parallel private(loc_partition_count)
-	    {
-		loc_partition_count = new  dim_t[mpiSize];
-		memset(loc_partition_count, 0, mpiSize_size);
+        // create a new distribution and labelling of the DOF
+        const size_t mpiSize_size = mpiSize * sizeof(dim_t);
+        memset(new_distribution, 0, mpiSize_size);
+#pragma omp parallel
+        {
+            dim_t* loc_partition_count = new dim_t[mpiSize];
+            memset(loc_partition_count, 0, mpiSize_size);
 #pragma omp for private(i)
-		for (i = 0; i < myNumVertices; ++i)
-		    loc_partition_count[partition[i]]++;
+            for (i = 0; i < myNumVertices; ++i)
+                loc_partition_count[partition[i]]++;
 #pragma omp critical
-		{
-		    for (i = 0; i < mpiSize; ++i)
-			new_distribution[i] += loc_partition_count[i];
-		}
-		delete[] loc_partition_count;
-	    }
+            {
+                for (i = 0; i < mpiSize; ++i)
+                    new_distribution[i] += loc_partition_count[i];
+            }
+            delete[] loc_partition_count;
+        }
 #ifdef ESYS_MPI
-	    /* recvbuf will be the concatenation of each CPU's contribution to new_distribution */
-	    MPI_Allgather(new_distribution, mpiSize, MPI_INT, recvbuf, mpiSize, MPI_INT, in->MPIInfo->comm);
+        // recvbuf will be the concatenation of each CPU's contribution to
+        // new_distribution
+        MPI_Allgather(new_distribution, mpiSize, MPI_INT, recvbuf, mpiSize, MPI_INT, in->MPIInfo->comm);
 #else
-	    for (i = 0; i < mpiSize; ++i)
-		recvbuf[i] = new_distribution[i];
+        for (i = 0; i < mpiSize; ++i)
+            recvbuf[i] = new_distribution[i];
 #endif
-	    new_distribution[0] = 0;
-	    for (rank = 0; rank < mpiSize; rank++)
-	    {
-		c = 0;
-		for (i = 0; i < myRank; ++i)
-		    c += recvbuf[rank + mpiSize * i];
-		for (i = 0; i < myNumVertices; ++i)
-		{
-		    if (rank == partition[i])
-		    {
-			newGlobalDOFID[i] = new_distribution[rank] + c;
-			c++;
-		    }
-		}
-		for (i = myRank + 1; i < mpiSize; ++i)
-		    c += recvbuf[rank + mpiSize * i];
-		new_distribution[rank + 1] = new_distribution[rank] + c;
-	    }
-	    delete[] recvbuf;
+        new_distribution[0] = 0;
+        for (rank = 0; rank < mpiSize; rank++)
+        {
+            c = 0;
+            for (i = 0; i < myRank; ++i)
+                c += recvbuf[rank + mpiSize * i];
+            for (i = 0; i < myNumVertices; ++i)
+            {
+                if (rank == partition[i])
+                {
+                    newGlobalDOFID[i] = new_distribution[rank] + c;
+                    c++;
+                }
+            }
+            for (i = myRank + 1; i < mpiSize; ++i)
+                c += recvbuf[rank + mpiSize * i];
+            new_distribution[rank + 1] = new_distribution[rank] + c;
+        }
+        delete[] recvbuf;
 
-	    /* now the overlap needs to be created by sending the partition around */
+        // now the overlap needs to be created by sending the partition around
 #ifdef ESYS_MPI
-	    dest = esysUtils::mod_rank(mpiSize, myRank + 1);
-	    source = esysUtils::mod_rank(mpiSize, myRank - 1);
+        Esys_MPI_rank dest = esysUtils::mod_rank(mpiSize, myRank + 1);
+        Esys_MPI_rank source = esysUtils::mod_rank(mpiSize, myRank - 1);
 #endif
-	    current_rank = myRank;
+        Esys_MPI_rank current_rank = myRank;
 #pragma omp parallel for private(i)
-	    for (i = 0; i < in->Nodes->numNodes; ++i)
-		setNewDOFId[i] = TRUE;
+        for (i = 0; i < in->Nodes->numNodes; ++i)
+            setNewDOFId[i] = true;
 
-	    for (p = 0; p < mpiSize; ++p)
-	    {
+        for (dim_t p = 0; p < mpiSize; ++p)
+        {
+            index_t firstVertex = distribution[current_rank];
+            index_t lastVertex = distribution[current_rank + 1];
+#pragma omp parallel for private(i,k)
+            for (i = 0; i < in->Nodes->numNodes; ++i)
+            {
+                k = in->Nodes->globalDegreesOfFreedom[i];
+                if (setNewDOFId[i] && (firstVertex <= k) && (k < lastVertex))
+                {
+                    in->Nodes->globalDegreesOfFreedom[i] = newGlobalDOFID[k - firstVertex];
+                    setNewDOFId[i] = false;
+                }
+            }
 
-		firstVertex = distribution[current_rank];
-		lastVertex = distribution[current_rank + 1];
-#pragma omp parallel for private(i,j,k)
-		for (i = 0; i < in->Nodes->numNodes; ++i)
-		{
-		    k = in->Nodes->globalDegreesOfFreedom[i];
-		    if (setNewDOFId[i] && (firstVertex <= k) && (k < lastVertex))
-		    {
-			in->Nodes->globalDegreesOfFreedom[i] = newGlobalDOFID[k - firstVertex];
-			setNewDOFId[i] = FALSE;
-		    }
-		}
-
-		if (p < mpiSize - 1)
-		{		/* the final send can be skipped */
+            if (p < mpiSize - 1)
+            {               /* the final send can be skipped */
 #ifdef ESYS_MPI
-		    MPI_Sendrecv_replace(newGlobalDOFID, len, MPI_INT,
-					 dest, in->MPIInfo->msg_tag_counter,
-					 source, in->MPIInfo->msg_tag_counter, in->MPIInfo->comm, &status);
+                MPI_Status status;
+                MPI_Sendrecv_replace(newGlobalDOFID, len, MPI_INT,
+                                     dest, in->MPIInfo->msg_tag_counter,
+                                     source, in->MPIInfo->msg_tag_counter, in->MPIInfo->comm, &status);
 #endif
-		    in->MPIInfo->msg_tag_counter++;
-		    current_rank = esysUtils::mod_rank(mpiSize, current_rank - 1);
-		}
-	    }
-	    for (i = 0; i < mpiSize + 1; ++i)
-		distribution[i] = new_distribution[i];
-	}
+                in->MPIInfo->msg_tag_counter++;
+                current_rank = esysUtils::mod_rank(mpiSize, current_rank - 1);
+            }
+        }
+        for (i = 0; i < mpiSize + 1; ++i)
+            distribution[i] = new_distribution[i];
     }
     delete[] newGlobalDOFID;
     delete[] setNewDOFId;
     delete[] new_distribution;
     delete[] partition_count;
     delete[] partition;
-    delete[] xyz;
-    return;
 }
+
diff --git a/dudley/src/Mesh_optimizeDOFLabeling.cpp b/dudley/src/Mesh_optimizeDOFLabeling.cpp
index 12e211c..5594e4d 100644
--- a/dudley/src/Mesh_optimizeDOFLabeling.cpp
+++ b/dudley/src/Mesh_optimizeDOFLabeling.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /**********************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #include "IndexList.h"
 
diff --git a/dudley/src/Mesh_prepare.cpp b/dudley/src/Mesh_prepare.cpp
index 37c175e..b572e8d 100644
--- a/dudley/src/Mesh_prepare.cpp
+++ b/dudley/src/Mesh_prepare.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh_print.cpp b/dudley/src/Mesh_print.cpp
index 38889ab..1731a6b 100644
--- a/dudley/src/Mesh_print.cpp
+++ b/dudley/src/Mesh_print.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh_read.cpp b/dudley/src/Mesh_read.cpp
index 3ee1692..c63ade9 100644
--- a/dudley/src/Mesh_read.cpp
+++ b/dudley/src/Mesh_read.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ctype.h>
 #include "Mesh.h"
 
diff --git a/dudley/src/Mesh_readGmsh.cpp b/dudley/src/Mesh_readGmsh.cpp
index d571126..3cd8355 100644
--- a/dudley/src/Mesh_readGmsh.cpp
+++ b/dudley/src/Mesh_readGmsh.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #include <stdio.h>
 
diff --git a/dudley/src/Mesh_relableElementNodes.cpp b/dudley/src/Mesh_relableElementNodes.cpp
index a5cd8a6..56165fb 100644
--- a/dudley/src/Mesh_relableElementNodes.cpp
+++ b/dudley/src/Mesh_relableElementNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh_resolveNodeIds.cpp b/dudley/src/Mesh_resolveNodeIds.cpp
index 75e40a8..c5e4345 100644
--- a/dudley/src/Mesh_resolveNodeIds.cpp
+++ b/dudley/src/Mesh_resolveNodeIds.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,6 +26,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #include "Util.h"
 
diff --git a/dudley/src/Mesh_setCoordinates.cpp b/dudley/src/Mesh_setCoordinates.cpp
index 407a26f..ca638ee 100644
--- a/dudley/src/Mesh_setCoordinates.cpp
+++ b/dudley/src/Mesh_setCoordinates.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,15 +20,15 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
 
-void Dudley_Mesh_setCoordinates(Dudley_Mesh * self, escriptDataC * newX)
+void Dudley_Mesh_setCoordinates(Dudley_Mesh * self, const escript::Data* newX)
 {
     Dudley_NodeFile_setCoordinates(self->Nodes, newX);
 }
 
-/*
-* $Log$
-*/
diff --git a/dudley/src/Mesh_tagmaps.cpp b/dudley/src/Mesh_tagmaps.cpp
index be594df..811c7ae 100644
--- a/dudley/src/Mesh_tagmaps.cpp
+++ b/dudley/src/Mesh_tagmaps.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/Mesh_tet4.cpp b/dudley/src/Mesh_tet4.cpp
index 0491d57..c5bb2bf 100644
--- a/dudley/src/Mesh_tet4.cpp
+++ b/dudley/src/Mesh_tet4.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "TriangularMesh.h"
 
 /* Be careful reading this function. The X? and NStride? are 1,2,3 but the loop vars are 0,1,2 */
diff --git a/dudley/src/Mesh_tri3.cpp b/dudley/src/Mesh_tri3.cpp
index 7a1d821..bcc1aee 100644
--- a/dudley/src/Mesh_tri3.cpp
+++ b/dudley/src/Mesh_tri3.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "TriangularMesh.h"
 
 Dudley_Mesh *Dudley_TriangularMesh_Tri3(dim_t * numElements,
diff --git a/dudley/src/Mesh_write.cpp b/dudley/src/Mesh_write.cpp
index f42d2c7..f886c94 100644
--- a/dudley/src/Mesh_write.cpp
+++ b/dudley/src/Mesh_write.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 /************************************************************************************/
diff --git a/dudley/src/NodeFile.cpp b/dudley/src/NodeFile.cpp
index b3feee7..27b4846 100644
--- a/dudley/src/NodeFile.cpp
+++ b/dudley/src/NodeFile.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 /*                                                             */
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/NodeFile.h b/dudley/src/NodeFile.h
index 24adaf4..9a9221c 100644
--- a/dudley/src/NodeFile.h
+++ b/dudley/src/NodeFile.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -138,8 +138,8 @@ void Dudley_NodeFile_setGlobalNodeIDIndexRange(index_t * min_id, index_t * max_i
 void Dudley_NodeFile_setGlobalReducedNodeIDIndexRange(index_t * min_id, index_t * max_id, Dudley_NodeFile * in);
 
 /* ===================== */
-void Dudley_NodeFile_setCoordinates(Dudley_NodeFile *, escriptDataC *);
-void Dudley_NodeFile_setTags(Dudley_NodeFile *, const int, escriptDataC *);
+void Dudley_NodeFile_setCoordinates(Dudley_NodeFile *, const escript::Data *);
+void Dudley_NodeFile_setTags(Dudley_NodeFile *, const int, const escript::Data *);
 void Dudley_NodeFile_setTagsInUse(Dudley_NodeFile * in);
 
 #endif
diff --git a/dudley/src/NodeFile_allocTable.cpp b/dudley/src/NodeFile_allocTable.cpp
index 31c326b..befaab4 100644
--- a/dudley/src/NodeFile_allocTable.cpp
+++ b/dudley/src/NodeFile_allocTable.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 #include "Util.h"
 
diff --git a/dudley/src/NodeFile_copyTable.cpp b/dudley/src/NodeFile_copyTable.cpp
index 0d15828..b936668 100644
--- a/dudley/src/NodeFile_copyTable.cpp
+++ b/dudley/src/NodeFile_copyTable.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/NodeFile_createDenseLabelings.cpp b/dudley/src/NodeFile_createDenseLabelings.cpp
index 4e848e0..fb2c2b6 100644
--- a/dudley/src/NodeFile_createDenseLabelings.cpp
+++ b/dudley/src/NodeFile_createDenseLabelings.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/NodeFile_gather.cpp b/dudley/src/NodeFile_gather.cpp
index dac172a..86eb8db 100644
--- a/dudley/src/NodeFile_gather.cpp
+++ b/dudley/src/NodeFile_gather.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
  *
  ************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/NodeFile_scatter.cpp b/dudley/src/NodeFile_scatter.cpp
index 39a2faf..0fca4fa 100644
--- a/dudley/src/NodeFile_scatter.cpp
+++ b/dudley/src/NodeFile_scatter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 
 /************************************************************************************/
diff --git a/dudley/src/NodeFile_setCoordinates.cpp b/dudley/src/NodeFile_setCoordinates.cpp
index fde5d63..5fba5ca 100644
--- a/dudley/src/NodeFile_setCoordinates.cpp
+++ b/dudley/src/NodeFile_setCoordinates.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,12 +22,15 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 #include "Util.h"
 
 /************************************************************************************/
 
-void Dudley_NodeFile_setCoordinates(Dudley_NodeFile * self, escriptDataC * newX)
+void Dudley_NodeFile_setCoordinates(Dudley_NodeFile * self, const escript::Data* newX)
 {
     char error_msg[LenErrorMsg_MAX];
     size_t numDim_size;
diff --git a/dudley/src/NodeFile_setIdRange.cpp b/dudley/src/NodeFile_setIdRange.cpp
index a6d0102..689ead6 100644
--- a/dudley/src/NodeFile_setIdRange.cpp
+++ b/dudley/src/NodeFile_setIdRange.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 #include "Util.h"
 
diff --git a/dudley/src/NodeFile_setTags.cpp b/dudley/src/NodeFile_setTags.cpp
index 9bb2bd4..3d3e03a 100644
--- a/dudley/src/NodeFile_setTags.cpp
+++ b/dudley/src/NodeFile_setTags.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,12 +22,15 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 #include "Util.h"
 
 /************************************************************************************/
 
-void Dudley_NodeFile_setTags(Dudley_NodeFile * self, const int newTag, escriptDataC * mask)
+void Dudley_NodeFile_setTags(Dudley_NodeFile * self, const int newTag, const escript::Data* mask)
 {
     register dim_t n;
     dim_t numNodes;
diff --git a/dudley/src/NodeMapping.cpp b/dudley/src/NodeMapping.cpp
index d0cc228..4a79389 100644
--- a/dudley/src/NodeMapping.cpp
+++ b/dudley/src/NodeMapping.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/NodeMapping.h b/dudley/src/NodeMapping.h
index 342a37d..b7a2afa 100644
--- a/dudley/src/NodeMapping.h
+++ b/dudley/src/NodeMapping.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/SConscript b/dudley/src/SConscript
index f4bafc8..e7fc75b 100644
--- a/dudley/src/SConscript
+++ b/dudley/src/SConscript
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/dudley/src/ShapeTable.cpp b/dudley/src/ShapeTable.cpp
index bbcaf31..6242961 100644
--- a/dudley/src/ShapeTable.cpp
+++ b/dudley/src/ShapeTable.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/ShapeTable.h b/dudley/src/ShapeTable.h
index 1c5f716..6ff1641 100644
--- a/dudley/src/ShapeTable.h
+++ b/dudley/src/ShapeTable.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/TagMap.cpp b/dudley/src/TagMap.cpp
index 13a52b8..03dc78f 100644
--- a/dudley/src/TagMap.cpp
+++ b/dudley/src/TagMap.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/TagMap.h b/dudley/src/TagMap.h
index bedaa18..c6e7467 100644
--- a/dudley/src/TagMap.h
+++ b/dudley/src/TagMap.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/TriangularMesh.h b/dudley/src/TriangularMesh.h
index c3330b7..30c689e 100644
--- a/dudley/src/TriangularMesh.h
+++ b/dudley/src/TriangularMesh.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/Util.cpp b/dudley/src/Util.cpp
index 4493ade..eb1611b 100644
--- a/dudley/src/Util.cpp
+++ b/dudley/src/Util.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/Util.h b/dudley/src/Util.h
index aa1b408..a30929e 100644
--- a/dudley/src/Util.h
+++ b/dudley/src/Util.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/src/generateReferenceElementList.py b/dudley/src/generateReferenceElementList.py
index 05f7214..a8232c7 100644
--- a/dudley/src/generateReferenceElementList.py
+++ b/dudley/src/generateReferenceElementList.py
@@ -1,6 +1,6 @@
 #*******************************************************
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/dudley/test/MeshAdapterTestCase.cpp b/dudley/test/MeshAdapterTestCase.cpp
index 599f80a..c0412ed 100644
--- a/dudley/test/MeshAdapterTestCase.cpp
+++ b/dudley/test/MeshAdapterTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "MeshAdapterTestCase.h"
 
diff --git a/dudley/test/MeshAdapterTestCase.h b/dudley/test/MeshAdapterTestCase.h
index d459d08..cf2acd9 100644
--- a/dudley/test/MeshAdapterTestCase.h
+++ b/dudley/test/MeshAdapterTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/test/SConscript b/dudley/test/SConscript
index 51fde18..2f949c5 100644
--- a/dudley/test/SConscript
+++ b/dudley/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/dudley/test/dudley_UnitTests.cpp b/dudley/test/dudley_UnitTests.cpp
index bfaf265..7da6582 100644
--- a/dudley/test/dudley_UnitTests.cpp
+++ b/dudley/test/dudley_UnitTests.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/dudley/test/python/FCT_benchmark.py b/dudley/test/python/FCT_benchmark.py
index 8f2aa7d..2ed02fe 100755
--- a/dudley/test/python/FCT_benchmark.py
+++ b/dudley/test/python/FCT_benchmark.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/FCT_test1.py b/dudley/test/python/FCT_test1.py
index 2f801b7..3ce968b 100644
--- a/dudley/test/python/FCT_test1.py
+++ b/dudley/test/python/FCT_test1.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/FCT_test2.py b/dudley/test/python/FCT_test2.py
index 88c8ca1..e2a4914 100644
--- a/dudley/test/python/FCT_test2.py
+++ b/dudley/test/python/FCT_test2.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 from __future__ import print_function
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/OutTest.py b/dudley/test/python/OutTest.py
index e93f460..344d685 100644
--- a/dudley/test/python/OutTest.py
+++ b/dudley/test/python/OutTest.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/PoissonSolverTest.py b/dudley/test/python/PoissonSolverTest.py
index 25c609e..535e4a9 100644
--- a/dudley/test/python/PoissonSolverTest.py
+++ b/dudley/test/python/PoissonSolverTest.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/RecTest.py b/dudley/test/python/RecTest.py
index d018a8c..5833aa7 100644
--- a/dudley/test/python/RecTest.py
+++ b/dudley/test/python/RecTest.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/SConscript b/dudley/test/python/SConscript
index 649e02f..c34e458 100644
--- a/dudley/test/python/SConscript
+++ b/dudley/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -73,6 +73,8 @@ env.Alias('scalable_tests', [os.path.splitext(x)[0]+'.passed' for x in scalable_
 program = local_env.RunPyUnitTest(alltestruns)
 Depends(program, py_wrapper_lib)
 Depends(program, 'build_py_tests')
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # Add a group of tests
 from grouptest import *
diff --git a/dudley/test/python/axisymm-splitB.py b/dudley/test/python/axisymm-splitB.py
index e1e5394..5108133 100755
--- a/dudley/test/python/axisymm-splitB.py
+++ b/dudley/test/python/axisymm-splitB.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/blocktest.py b/dudley/test/python/blocktest.py
index 451a47b..92652bb 100755
--- a/dudley/test/python/blocktest.py
+++ b/dudley/test/python/blocktest.py
@@ -12,7 +12,7 @@
 #
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -25,7 +25,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/brick.py b/dudley/test/python/brick.py
index 917f8d9..7430017 100644
--- a/dudley/test/python/brick.py
+++ b/dudley/test/python/brick.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/convection.py b/dudley/test/python/convection.py
index 1c56d8b..729d736 100644
--- a/dudley/test/python/convection.py
+++ b/dudley/test/python/convection.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -18,7 +18,7 @@ this is a convection simulation over a domain [0,L] X [0,L] x [0,H]
 It is solved in dimensionless form
 
 """
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/fixme_run_generators.py b/dudley/test/python/fixme_run_generators.py
index 46f0e9d..e91571a 100644
--- a/dudley/test/python/fixme_run_generators.py
+++ b/dudley/test/python/fixme_run_generators.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/generate_dumps.py b/dudley/test/python/generate_dumps.py
index 2519f47..e425f70 100644
--- a/dudley/test/python/generate_dumps.py
+++ b/dudley/test/python/generate_dumps.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/generate_meshes.py b/dudley/test/python/generate_meshes.py
index dc9e1fb..837a054 100644
--- a/dudley/test/python/generate_meshes.py
+++ b/dudley/test/python/generate_meshes.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/linearElastic.py b/dudley/test/python/linearElastic.py
index 43a52a8..4adba87 100755
--- a/dudley/test/python/linearElastic.py
+++ b/dudley/test/python/linearElastic.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/rayleigh_taylor_instabilty.py b/dudley/test/python/rayleigh_taylor_instabilty.py
index 6bd0921..2ec823a 100644
--- a/dudley/test/python/rayleigh_taylor_instabilty.py
+++ b/dudley/test/python/rayleigh_taylor_instabilty.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/rectangle.py b/dudley/test/python/rectangle.py
index 043ba65..296aa02 100644
--- a/dudley/test/python/rectangle.py
+++ b/dudley/test/python/rectangle.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/run_escriptOnDudley.py b/dudley/test/python/run_escriptOnDudley.py
index b347ee3..98d19f7 100644
--- a/dudley/test/python/run_escriptOnDudley.py
+++ b/dudley/test/python/run_escriptOnDudley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -134,6 +134,7 @@ class Test_TableInterpolationOnDudley(Test_TableInterpolation):
 
 class Test_CSVOnDudley(Test_saveCSV):
     def setUp(self):
+        self.workdir=DUDLEY_WORKDIR
         NE0=NE
         NE1=NE+1
         self.domain=Rectangle(NE0,NE1)
diff --git a/dudley/test/python/run_inputOutput.py b/dudley/test/python/run_inputOutput.py
index 54e8086..b6db161 100644
--- a/dudley/test/python/run_inputOutput.py
+++ b/dudley/test/python/run_inputOutput.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/run_linearPDEsOnDudley1.py b/dudley/test/python/run_linearPDEsOnDudley1.py
index bb08848..fb4da76 100644
--- a/dudley/test/python/run_linearPDEsOnDudley1.py
+++ b/dudley/test/python/run_linearPDEsOnDudley1.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/dudley/test/python/run_linearPDEsOnDudley2.py b/dudley/test/python/run_linearPDEsOnDudley2.py
index 2af9b62..059ed19 100644
--- a/dudley/test/python/run_linearPDEsOnDudley2.py
+++ b/dudley/test/python/run_linearPDEsOnDudley2.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/dudley/test/python/run_models.py b/dudley/test/python/run_models.py
index b5acd86..e7fd194 100644
--- a/dudley/test/python/run_models.py
+++ b/dudley/test/python/run_models.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/run_nlpde2dOnDudley.py b/dudley/test/python/run_nlpde2dOnDudley.py
index c10e15f..a0bb44b 100644
--- a/dudley/test/python/run_nlpde2dOnDudley.py
+++ b/dudley/test/python/run_nlpde2dOnDudley.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/dudley/test/python/run_nlpde3dOnDudley.py b/dudley/test/python/run_nlpde3dOnDudley.py
index 3196671..ab790fd 100644
--- a/dudley/test/python/run_nlpde3dOnDudley.py
+++ b/dudley/test/python/run_nlpde3dOnDudley.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/dudley/test/python/run_simplesolve.py b/dudley/test/python/run_simplesolve.py
index 6ccbb3d..b806bbe 100644
--- a/dudley/test/python/run_simplesolve.py
+++ b/dudley/test/python/run_simplesolve.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/run_utilOnDudley.py b/dudley/test/python/run_utilOnDudley.py
index c0c0b51..6a22e6e 100644
--- a/dudley/test/python/run_utilOnDudley.py
+++ b/dudley/test/python/run_utilOnDudley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -43,6 +43,11 @@ try:
 except KeyError:
      DUDLEY_TEST_DATA='.'
 
+try:
+     DUDLEY_WORKDIR=os.environ['DUDLEY_WORKDIR']
+except KeyError:
+     DUDLEY_WORKDIR='.'
+
 DUDLEY_TEST_MESH_PATH=os.path.join(DUDLEY_TEST_DATA,"data_meshes")
 
 
@@ -52,6 +57,8 @@ class Test_UtilOnDudley(Test_util,Test_symfuncs):
    def setUp(self):
        self.domain =Rectangle(NE,NE+1,1)
        self.functionspace = FunctionOnBoundary(self.domain) # due to a bug in escript python needs to hold a reference to the domain
+       self.workdir=DUDLEY_WORKDIR
+
    def tearDown(self):
        del self.functionspace
        del self.domain
diff --git a/dudley/test/python/seismic_wave.py b/dudley/test/python/seismic_wave.py
index 9ccc741..7030d15 100644
--- a/dudley/test/python/seismic_wave.py
+++ b/dudley/test/python/seismic_wave.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/slip_stress_mesh_old.py b/dudley/test/python/slip_stress_mesh_old.py
index 71d94a6..6d4ec85 100644
--- a/dudley/test/python/slip_stress_mesh_old.py
+++ b/dudley/test/python/slip_stress_mesh_old.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/slip_stress_old.py b/dudley/test/python/slip_stress_old.py
index ce55896..cdf3ec2 100644
--- a/dudley/test/python/slip_stress_old.py
+++ b/dudley/test/python/slip_stress_old.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/stokes_problems.py b/dudley/test/python/stokes_problems.py
index d5643a6..ef2cd98 100644
--- a/dudley/test/python/stokes_problems.py
+++ b/dudley/test/python/stokes_problems.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/subduction1.py b/dudley/test/python/subduction1.py
index ea95169..95373f4 100644
--- a/dudley/test/python/subduction1.py
+++ b/dudley/test/python/subduction1.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/subduction1_gen.py b/dudley/test/python/subduction1_gen.py
index 1c20b60..8b5d791 100644
--- a/dudley/test/python/subduction1_gen.py
+++ b/dudley/test/python/subduction1_gen.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/time_chunks.py b/dudley/test/python/time_chunks.py
index 0cdce6d..ae57818 100644
--- a/dudley/test/python/time_chunks.py
+++ b/dudley/test/python/time_chunks.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/dudley/test/python/tp.py b/dudley/test/python/tp.py
index b75b30c..da49c4c 100644
--- a/dudley/test/python/tp.py
+++ b/dudley/test/python/tp.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escript/py_src/SConscript b/escript/py_src/SConscript
index 5846e10..55d370e 100644
--- a/escript/py_src/SConscript
+++ b/escript/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2013-2014 by University of Queensland
+# Copyright (c) 2013-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/escript/py_src/__init__.py b/escript/py_src/__init__.py
index a74d5c5..97437e7 100644
--- a/escript/py_src/__init__.py
+++ b/escript/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2013-2014 by University of Queensland
+# Copyright (c) 2013-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2013-2014 by University of Queensland
+__copyright__="""Copyright (c) 2013-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -25,3 +25,4 @@ from esys.escriptcore.util import *
 from esys.escriptcore.nonlinearPDE import NonlinearPDE
 from esys.escriptcore.datamanager import DataManager
 from esys.escriptcore.symbolic import *
+from esys.escriptcore.splitworld import *
diff --git a/escriptcore/py_src/SConscript b/escriptcore/py_src/SConscript
index 240b77a..8044969 100644
--- a/escriptcore/py_src/SConscript
+++ b/escriptcore/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/escriptcore/py_src/__init__.py b/escriptcore/py_src/__init__.py
index b204fc2..b45e86c 100644
--- a/escriptcore/py_src/__init__.py
+++ b/escriptcore/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/benchmark.py b/escriptcore/py_src/benchmark.py
index 36de1a9..b448218 100644
--- a/escriptcore/py_src/benchmark.py
+++ b/escriptcore/py_src/benchmark.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/datamanager.py b/escriptcore/py_src/datamanager.py
index 8ab869d..c909434 100644
--- a/escriptcore/py_src/datamanager.py
+++ b/escriptcore/py_src/datamanager.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/domainCouplers.py b/escriptcore/py_src/domainCouplers.py
index aee2356..2eb0a15 100644
--- a/escriptcore/py_src/domainCouplers.py
+++ b/escriptcore/py_src/domainCouplers.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2014 by University of Queensland
+# Copyright (c) 2014-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -21,7 +21,7 @@ must already support interpolation in at least one direction.
 
 """
 
-__copyright__="""Copyright (c) 2014 by University of Queensland
+__copyright__="""Copyright (c) 2014-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -157,7 +157,7 @@ class SpeckleyToRipley(object):
         """
         Returns the shape of the domains
 
-       :return: A ``tuple`` of the two shape ``tuple``s in the form
+       :return: A ``tuple`` of the two shape ``tuples`` in the form
                 (speckley, ripley)
        :rtype: ``tuple`` of ``tuple`` of ``int``
         """
diff --git a/escriptcore/py_src/faultsystems.py b/escriptcore/py_src/faultsystems.py
index 770bcfe..9847683 100644
--- a/escriptcore/py_src/faultsystems.py
+++ b/escriptcore/py_src/faultsystems.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/flows.py b/escriptcore/py_src/flows.py
index 8123684..26b2d8d 100644
--- a/escriptcore/py_src/flows.py
+++ b/escriptcore/py_src/flows.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/gmshrunner.py b/escriptcore/py_src/gmshrunner.py
index 0ab0f25..3b26c95 100644
--- a/escriptcore/py_src/gmshrunner.py
+++ b/escriptcore/py_src/gmshrunner.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -49,7 +49,7 @@ def _runGmshPy(geoFile, mshFile, numDim, order, verbosity):
         incomplete=False
         model.setOrderN(order, linear, incomplete)
         model.mesh(numDim)
-        ret = model.writeMSH(mshFile)==1
+        ret = model.writeMSH(mshFile)==0 # 0 indicates error for gmshpy
         gmshpy.GmshClearProject()
     else:
         ret = 0
@@ -59,14 +59,15 @@ def _runGmshPy(geoFile, mshFile, numDim, order, verbosity):
 def _runGmshSerial(geoFile, mshFile, numDim, order, verbosity):
     if getMPIRankWorld() == 0:
         import shlex, subprocess
-        cmdline = "gmsh -format msh -%s -order %s -v %s -o '%s' '%s'"%(numDim, order, verbosity, mshFile, geoFile)
+        cmdline = "gmsh -format msh -%s -order %s -o '%s' '%s'"%(numDim, order, mshFile, geoFile)
         args = shlex.split(cmdline)
         try:
             ret = subprocess.call(args)
-        except:
+        except Exception as e:
             ret = 1
     else:
         ret = 0
+   
     ret=getMPIWorldMax(ret)
     return ret
 
@@ -78,10 +79,11 @@ def _runGmshMPI(geoFile, mshFile, numDim, order, verbosity):
     cmdline = "gmsh -format msh -%s -order %s -v %s -o '%s' '%s'"%(numDim, order, verbosity, mshFile, geoFile)
     args = shlex.split(cmdline)
     ret = runMPIProgram(args)
-    # runMPIProgram returns immediately so wait 'a bit' to let gmsh finish
-    # (which is still not guaranteed, see bug #33)
-    sleep(10)
-    return ret
+    # on Windows runMPIProgram returns immediately so wait 'a bit' to let gmsh finish
+    import os
+    if os.name == "nt":
+        sleep(10)
+    return ret #already MPI distributed
 
 def gmshGeo2Msh(geoFile, mshFile, numDim, order=1, verbosity=0):
     """
diff --git a/escriptcore/py_src/heat.py b/escriptcore/py_src/heat.py
index 8f65b88..0efed1b 100644
--- a/escriptcore/py_src/heat.py
+++ b/escriptcore/py_src/heat.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/levelset.py b/escriptcore/py_src/levelset.py
index c8c8a24..0ce35d3 100644
--- a/escriptcore/py_src/levelset.py
+++ b/escriptcore/py_src/levelset.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/linearPDEs.py b/escriptcore/py_src/linearPDEs.py
index 7f2bf16..679bcf6 100644
--- a/escriptcore/py_src/linearPDEs.py
+++ b/escriptcore/py_src/linearPDEs.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -242,6 +242,9 @@ class PDECoef(object):
               if not newValue.getFunctionSpace() == self.getFunctionSpace(domain,reducedEquationOrder,reducedSolutionOrder):
                 try:
                   newValue=escore.Data(newValue,self.getFunctionSpace(domain,reducedEquationOrder,reducedSolutionOrder))
+                except RuntimeError as er:
+                 msg="Attempting to interpolate coefficient to function space %s encountered the followin error: %s"%(self.getFunctionSpace(domain),str(er))
+                 raise IllegalCoefficientFunctionSpace(msg)
                 except:
                   raise IllegalCoefficientFunctionSpace("Unable to interpolate coefficient to function space %s"%self.getFunctionSpace(domain))
        else:
diff --git a/escriptcore/py_src/modelframe.py b/escriptcore/py_src/modelframe.py
index 7a3e5c8..4c8d431 100644
--- a/escriptcore/py_src/modelframe.py
+++ b/escriptcore/py_src/modelframe.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/models.py b/escriptcore/py_src/models.py
index 29eebcf..3699f14 100644
--- a/escriptcore/py_src/models.py
+++ b/escriptcore/py_src/models.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/mountains.py b/escriptcore/py_src/mountains.py
index 93a10c7..b09550b 100644
--- a/escriptcore/py_src/mountains.py
+++ b/escriptcore/py_src/mountains.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/nonlinearPDE.py b/escriptcore/py_src/nonlinearPDE.py
index 87016cc..19b1eeb 100644
--- a/escriptcore/py_src/nonlinearPDE.py
+++ b/escriptcore/py_src/nonlinearPDE.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/pdetools.py b/escriptcore/py_src/pdetools.py
index 170d774..4aeb3da 100644
--- a/escriptcore/py_src/pdetools.py
+++ b/escriptcore/py_src/pdetools.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/rheologies.py b/escriptcore/py_src/rheologies.py
index 119ab1f..130c4a7 100644
--- a/escriptcore/py_src/rheologies.py
+++ b/escriptcore/py_src/rheologies.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/runmodel.py b/escriptcore/py_src/runmodel.py
index 0c194d6..2744341 100644
--- a/escriptcore/py_src/runmodel.py
+++ b/escriptcore/py_src/runmodel.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/splitworld.py b/escriptcore/py_src/splitworld.py
index ffdbc8d..6627f8d 100644
--- a/escriptcore/py_src/splitworld.py
+++ b/escriptcore/py_src/splitworld.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2014 by University of Queensland
+# Copyright (c) 2014-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2014 by University of Queensland
+__copyright__="""Copyright (c) 2014-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -65,6 +65,15 @@ class Job(object):
     self.wantedvalues=[]                # names of shared values this job wishes to import    
     self.importedvalues={}      # name:values of which this jobs wants to use
     self.exportedvalues={}      # name:values exported by this job
+    self.swcount=kwargs["swcount"]      # How many subworlds are there?
+    self.swid=kwargs["swid"]    # which subworld are we running in?
+    
+    
+  def wantValue(self, name):
+    """
+    Register your interest in importing a variable with the given name
+    """
+    self.wantedvalues.append(name)
     
   def setImportValue(self, name, v):
     """
@@ -74,7 +83,7 @@ class Job(object):
     :var v: value to be imported
     :type v: ?
     """
-    pass
+    self.importedvalues[name]=v
   
   
   def getExportValue(self, name):
@@ -99,12 +108,13 @@ class Job(object):
   def importValue(self, name):
     """
     For use inside the work() method.
-    :var name: label for imported value. Returns None if import not present.
+    :var name: label for imported value.
     :type name: ``str``
     """
     if name in self.importedvalues:
         return self.importedvalues[name]
     else:
+        raise KeyError("Attempt to import variable \'"+name+"\' which is not available to this job.")
         return None
 
   def clearExports(self):
@@ -134,4 +144,25 @@ class Job(object):
     A return value of True, indicates this job thinks it is done.
     A return value of False indicates work still to be done
     """
-    return True
\ No newline at end of file
+    return True
+
+class FunctionJob(Job):
+  """
+  Takes a python function (with only keyword params) to be called as the work method
+  """
+  def __init__(self, fn, *args, **kwargs):
+    super(FunctionJob, self).__init__(*args, **kwargs)
+    self.__fn__ = fn
+    self.__calldict__ = kwargs
+    if "imports" in kwargs:
+      if isinstance(kwargs["imports"], str):
+        self.requestImport(kwargs["imports"])
+      else:
+        for n in kwargs["imports"]:
+          self.requestImport(n)
+
+  def work(self):
+    self.__fn__(self, **self.__calldict__)
+    return True
+
+    
\ No newline at end of file
diff --git a/escriptcore/py_src/start.py b/escriptcore/py_src/start.py
index d7bd244..937fe85 100644
--- a/escriptcore/py_src/start.py
+++ b/escriptcore/py_src/start.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/symbolic/__init__.py b/escriptcore/py_src/symbolic/__init__.py
index a02c754..f89776d 100644
--- a/escriptcore/py_src/symbolic/__init__.py
+++ b/escriptcore/py_src/symbolic/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/symbolic/evaluator.py b/escriptcore/py_src/symbolic/evaluator.py
index 27aa555..057618a 100644
--- a/escriptcore/py_src/symbolic/evaluator.py
+++ b/escriptcore/py_src/symbolic/evaluator.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -22,6 +22,8 @@ http://www.opensource.org/licenses/osl-3.0.php"""
 __url__="https://launchpad.net/escript-finley"
 __author__="Cihan Altinay"
 
+__all__ = ['Evaluator']
+
 import distutils.version as duv
 
 """
diff --git a/escriptcore/py_src/symbolic/functions.py b/escriptcore/py_src/symbolic/functions.py
index 0a8e789..cec5ec3 100644
--- a/escriptcore/py_src/symbolic/functions.py
+++ b/escriptcore/py_src/symbolic/functions.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/symbolic/pretty.py b/escriptcore/py_src/symbolic/pretty.py
index 537a0ff..0b731e8 100644
--- a/escriptcore/py_src/symbolic/pretty.py
+++ b/escriptcore/py_src/symbolic/pretty.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/symbolic/symbol.py b/escriptcore/py_src/symbolic/symbol.py
index 8078504..f68cd37 100644
--- a/escriptcore/py_src/symbolic/symbol.py
+++ b/escriptcore/py_src/symbolic/symbol.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/symbolic/utils.py b/escriptcore/py_src/symbolic/utils.py
index d13300a..5f67207 100644
--- a/escriptcore/py_src/symbolic/utils.py
+++ b/escriptcore/py_src/symbolic/utils.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/testing.py b/escriptcore/py_src/testing.py
index 7fc7233..ff36169 100644
--- a/escriptcore/py_src/testing.py
+++ b/escriptcore/py_src/testing.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2014 by University of Queensland
+# Copyright (c) 2014-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -27,35 +27,30 @@ allowing access to list all skipped tests and other data kept by the
 
 Examples:
 
-  Running all test classes
-    ```
+Running all test classes::
+
     import your_test_module_or_file as tests
     tests.run_tests("your_test_module_or_file")
-    ```
 
-  Running specific test classes
-    ```
+Running specific test classes::
+
     import your_test_module_or_file as tests
-    tests.run_tests("your_test_module_or_file", [tests.Test_classA,
-            tests.Test_classB])
-    ```
-    
-  Running a specific test within a class
-    ```
+    tests.run_tests("your_test_module_or_file", [tests.Test_classA, tests.Test_classB])
+
+Running a specific test within a class::
+
     import your_test_module_or_file as tests
     tests.run_single_test(tests.Test_classname("test_functionname"))
-    ```
 
-  Printing the list of skipped tests
-    ```
+Printing the list of skipped tests::
+
     results = tests.run_tests("name")
     for skipped_test in results.skipped:
         print(skipped_test)
-    ```
 
 """
 
-__copyright__="""Copyright (c) 2014 by University of Queensland
+__copyright__="""Copyright (c) 2014-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/unitsSI.py b/escriptcore/py_src/unitsSI.py
index c2c3a94..8143ccc 100644
--- a/escriptcore/py_src/unitsSI.py
+++ b/escriptcore/py_src/unitsSI.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -80,7 +80,7 @@
 """
 
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/utestselect.py b/escriptcore/py_src/utestselect.py
index a9a0860..a4f4d6b 100644
--- a/escriptcore/py_src/utestselect.py
+++ b/escriptcore/py_src/utestselect.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2014 by University of Queensland
+# Copyright (c) 2014-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2014 by University of Queensland
+__copyright__="""Copyright (c) 2014-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/py_src/util.py b/escriptcore/py_src/util.py
index 0fac955..03dbd70 100644
--- a/escriptcore/py_src/util.py
+++ b/escriptcore/py_src/util.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/src/AbstractContinuousDomain.cpp b/escriptcore/src/AbstractContinuousDomain.cpp
index 5225032..eccbf5b 100644
--- a/escriptcore/src/AbstractContinuousDomain.cpp
+++ b/escriptcore/src/AbstractContinuousDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,7 +14,8 @@
 *
 *****************************************************************************/
 
-
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 #include "AbstractContinuousDomain.h"
 #include "Data.h"
 
diff --git a/escriptcore/src/AbstractContinuousDomain.h b/escriptcore/src/AbstractContinuousDomain.h
index 146abfc..9a026f0 100644
--- a/escriptcore/src/AbstractContinuousDomain.h
+++ b/escriptcore/src/AbstractContinuousDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/AbstractDomain.cpp b/escriptcore/src/AbstractDomain.cpp
index b5a779a..322d631 100644
--- a/escriptcore/src/AbstractDomain.cpp
+++ b/escriptcore/src/AbstractDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "AbstractDomain.h" 
 #include "DomainException.h"
 
diff --git a/escriptcore/src/AbstractDomain.h b/escriptcore/src/AbstractDomain.h
index ac81d31..0ac66ae 100644
--- a/escriptcore/src/AbstractDomain.h
+++ b/escriptcore/src/AbstractDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -18,16 +18,6 @@
 #ifndef __ESCRIPT_ABSTRACTDOMAIN_H__
 #define __ESCRIPT_ABSTRACTDOMAIN_H__
 
-#ifdef BADPYTHONMACROS
-// This hack is required for BSD/OSX builds with python 2.7
-// (and possibly others).  It must be the first include.
-// From bug reports online it seems that python redefines
-// some c macros that are functions in c++.
-// c++ doesn't like that!
-#include <Python.h>
-#undef BADPYTHONMACROS
-#endif
-
 #include "system_dep.h"
 #include "Pointers.h"
 #include "DataTypes.h"
diff --git a/escriptcore/src/SplitWorldException.cpp b/escriptcore/src/AbstractReducer.cpp
similarity index 51%
copy from escriptcore/src/SplitWorldException.cpp
copy to escriptcore/src/AbstractReducer.cpp
index 47bcd19..ea7b5bd 100644
--- a/escriptcore/src/SplitWorldException.cpp
+++ b/escriptcore/src/AbstractReducer.cpp
@@ -1,7 +1,6 @@
-
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,21 +13,36 @@
 *
 *****************************************************************************/
 
-// Adapted from FunctionSpaceException.cpp
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
-#include "SplitWorldException.h"
 
+#include <sstream>
+#include <limits>
+#include <boost/python/extract.hpp>
+#include <boost/scoped_array.hpp>
 
+#include "AbstractReducer.h"
+#include "SplitWorldException.h"
+
+using namespace boost::python;
 using namespace escript;
 
 
-const std::string 
-SplitWorldException::exceptionNameValue("SplitWorldException");
+const int AbstractReducer::PARAMTAG=120567;
 
+bool AbstractReducer::hasValue()
+{
+    return valueadded;
+}
+
+double AbstractReducer::getDouble()
+{
+    throw SplitWorldException("This reducer is not able to provide a single scalar.");  
+}
 
-const std::string &
-SplitWorldException::exceptionName() const
+void AbstractReducer::clear()
 {
-  return exceptionNameValue;
+    valueadded=false;
 }
 
diff --git a/escriptcore/src/Reducer.h b/escriptcore/src/AbstractReducer.h
similarity index 60%
rename from escriptcore/src/Reducer.h
rename to escriptcore/src/AbstractReducer.h
index 3dd0431..e61c390 100644
--- a/escriptcore/src/Reducer.h
+++ b/escriptcore/src/AbstractReducer.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,10 +26,14 @@ namespace escript
   
 namespace reducerstatus
 {
-const char NONE=0;  	// I have not value for this var and no interest in it
-const char INTERESTED=1;	// I am interested in this variable but I have no value for it
-const char HAVE=2;	// I have a new value for this variable
-const char ERROR='!';	// Something bad happened  
+  
+// Because these may be used in loops, the values must form a contiguous block (except ERROR)  
+const unsigned char NONE=0;  	// I have no value for this var and no interest in it
+const unsigned char INTERESTED=1;	// I am interested in this variable but I have no value for it
+const unsigned char OLD=2;	// I have a copy from elsewhere but no new values to contribute
+const unsigned char OLDINTERESTED=3;	// interested but only have a cached copy (no new values)
+const unsigned char NEW=4;	// I have a new value for this variable
+const unsigned char ERROR='!';	// Something bad happened  
 }
   
 // There is currently no way to get a completely generic result out of this
@@ -46,6 +50,8 @@ public:
 	// clear previous result ready for a new set of reductions
     virtual void reset()=0;
     
+    virtual std::string description()=0;
+    
 	// converse with other subworlds to ensure subtype information matches
 	// The main problem case here would be Data on different function spaces
 	// same communicator requirements for reduceRemoteValues
@@ -53,6 +59,14 @@ public:
 	// Must only be called on 
     virtual bool checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring)=0; 
     
+
+#ifdef ESYS_MPI  
+	// send from proc 0 in the communicator to all others
+    virtual bool groupSend(MPI_Comm& com)=0;
+    
+	// reduction with some procs submitting identity values
+    virtual bool groupReduce(MPI_Comm& com, char mystate)=0;  
+#endif  
     
 	// call to merge with values on other subworlds
 	// It does not take a value argument because local values should have 
@@ -60,7 +74,7 @@ public:
 	// Must only be called on participating SubWorlds
 	// the mpi_info holds a communicator linking corresponding processes
 	// in every participating subworld
-    virtual bool reduceRemoteValues(esysUtils::JMPI& mpi_info)=0;
+    virtual bool reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active)=0;
     
 	// true if at least one localValue has been added
 	// used to check if this subworld should participate in remote merges
@@ -74,59 +88,20 @@ public:
 	// This is not a reduction and will replace any existing value    
     virtual bool sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUtils::JMPI& mpiinfo)=0;
     
+    virtual double getDouble();
+   
+    virtual boost::python::object getPyObj()=0; 
+    
+    virtual void clear();
 protected:
+
     bool valueadded;
-    
+    static const int PARAMTAG;    
 };
 
 
 typedef boost::shared_ptr<AbstractReducer> Reducer_ptr;
 
-
-
-
-// Reduces using pointwise MPI operations
-class MPIDataReducer : public AbstractReducer
-{
-public:
-    MPIDataReducer(MPI_Op op);
-    ~MPIDataReducer(){};
-    
-        // This is not a constructor parameter because 
-        // if these are created outside the subworld, they won't have
-        // access to a domain yet.
-        // I also want SplitWorld to be able to set this
-    void setDomain(escript::Domain_ptr d);
-    bool valueCompatible(boost::python::object v);
-    bool reduceLocalValue(boost::python::object v, std::string& errstring);
-    void reset();
-    bool checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring);
-    
-    void getCompatibilityInfo(std::vector<unsigned>& params);
-    
-      // talk to corresponding processes in other subworlds
-    bool reduceRemoteValues(esysUtils::JMPI& mpi_info);
-    
-    
-    
-	// Get a value for this variable from another process
-	// This is not a reduction and will replace any existing value
-    bool recvFrom(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo);
-
-	// Send a value to this variable to another process
-	// This is not a reduction and will replace any existing value    
-    bool sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUtils::JMPI& mpiinfo);    
-    
-    
-    
-private:    
-    escript::Data value;
-    escript::const_Domain_ptr dom;
-    MPI_Op reduceop;
-};
-
-Reducer_ptr makeDataReducer(std::string type);
-
 }
 
 #endif // __ESCRIPT_REDUCER_H__
diff --git a/escriptcore/src/AbstractSystemMatrix.cpp b/escriptcore/src/AbstractSystemMatrix.cpp
index 5f8fb15..b0a4cd4 100644
--- a/escriptcore/src/AbstractSystemMatrix.cpp
+++ b/escriptcore/src/AbstractSystemMatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,7 +14,8 @@
 *
 *****************************************************************************/
 
-
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 #include "AbstractSystemMatrix.h" 
 #include "DataException.h"
 #include "Data.h"
diff --git a/escriptcore/src/AbstractSystemMatrix.h b/escriptcore/src/AbstractSystemMatrix.h
index b365fde..619830c 100644
--- a/escriptcore/src/AbstractSystemMatrix.h
+++ b/escriptcore/src/AbstractSystemMatrix.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/AbstractTransportProblem.cpp b/escriptcore/src/AbstractTransportProblem.cpp
index 5f005b9..7fa9997 100644
--- a/escriptcore/src/AbstractTransportProblem.cpp
+++ b/escriptcore/src/AbstractTransportProblem.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,7 +14,8 @@
 *
 *****************************************************************************/
 
-
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 #include "AbstractTransportProblem.h" 
 #include "TransportProblemException.h"
 #include "DataTypes.h"
diff --git a/escriptcore/src/AbstractTransportProblem.h b/escriptcore/src/AbstractTransportProblem.h
index 4bdc2a7..68f11a8 100644
--- a/escriptcore/src/AbstractTransportProblem.h
+++ b/escriptcore/src/AbstractTransportProblem.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/BinaryOp.h b/escriptcore/src/BinaryOp.h
index e33d702..eecd79e 100644
--- a/escriptcore/src/BinaryOp.h
+++ b/escriptcore/src/BinaryOp.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Data.cpp b/escriptcore/src/Data.cpp
index 8de7bc4..efc7c95 100644
--- a/escriptcore/src/Data.cpp
+++ b/escriptcore/src/Data.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "Data.h"
 
@@ -504,23 +506,6 @@ Data::initialise(const double value,
     }
 }
 
-
-escriptDataC
-Data::getDataC()
-{
-    escriptDataC temp;
-    temp.m_dataPtr=(void*)this;
-    return temp;
-}
-
-escriptDataC
-Data::getDataC() const
-{
-    escriptDataC temp;
-    temp.m_dataPtr=(void*)this;
-    return temp;
-}
-
 const bp::tuple
 Data::getShapeTuple() const
 {
@@ -2712,7 +2697,8 @@ Data::setTaggedValueByName(std::string name,
     }
     else
     {
-        throw DataException("Error - unknown tag in setTaggedValueByName.");
+        std::string msg="Error - unknown tag ("+name+") in setTaggedValueByName.";
+        throw DataException(msg);
     }
 }
 
diff --git a/escriptcore/src/Data.h b/escriptcore/src/Data.h
index a478e59..35763d8 100644
--- a/escriptcore/src/Data.h
+++ b/escriptcore/src/Data.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -29,10 +29,6 @@
 #include "UnaryOp.h"
 #include "DataException.h"
 
-
-
-#include "DataC.h"
-
 #ifdef _OPENMP
 #include <omp.h>
 #endif
@@ -328,24 +324,6 @@ class Data {
   int
   getTagNumber(int dpno);
 
-  /**
-     \brief
-     Return the C wrapper for the Data object.
-  */
-  ESCRIPT_DLL_API
-  escriptDataC
-  getDataC();
-
-
-
-  /**
-     \brief
-     Return the C wrapper for the Data object - const version.
-  */
-  ESCRIPT_DLL_API
-  escriptDataC
-  getDataC() const;
-
 
   /**
      \brief
diff --git a/escriptcore/src/DataAbstract.cpp b/escriptcore/src/DataAbstract.cpp
index 4d0a9a1..b16b939 100644
--- a/escriptcore/src/DataAbstract.cpp
+++ b/escriptcore/src/DataAbstract.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataAbstract.h"
 #include "DataException.h"
diff --git a/escriptcore/src/DataAbstract.h b/escriptcore/src/DataAbstract.h
index dc4cf9a..96bcfec 100644
--- a/escriptcore/src/DataAbstract.h
+++ b/escriptcore/src/DataAbstract.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataAlgorithm.h b/escriptcore/src/DataAlgorithm.h
index 28db760..51cfdb5 100644
--- a/escriptcore/src/DataAlgorithm.h
+++ b/escriptcore/src/DataAlgorithm.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataBlocks2D.cpp b/escriptcore/src/DataBlocks2D.cpp
index 42dce12..6d17524 100644
--- a/escriptcore/src/DataBlocks2D.cpp
+++ b/escriptcore/src/DataBlocks2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataBlocks2D.h b/escriptcore/src/DataBlocks2D.h
index 66747a5..56a901f 100644
--- a/escriptcore/src/DataBlocks2D.h
+++ b/escriptcore/src/DataBlocks2D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataC.cpp b/escriptcore/src/DataC.cpp
index 9b5fccd..5a7b221 100644
--- a/escriptcore/src/DataC.cpp
+++ b/escriptcore/src/DataC.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,164 +14,148 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "DataC.h"
 
 #include "Data.h"
 #include "DataTypes.h"
 
-int getFunctionSpaceType(struct escriptDataC* data) 
+int getFunctionSpaceType(const escript::Data* data) 
 {
-  escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-  return temp->getFunctionSpace().getTypeCode();
+  return data->getFunctionSpace().getTypeCode();
 }
 
 
-int isDataPointShapeEqual(struct escriptDataC* data, int rank, const int* dimensions)
+int isDataPointShapeEqual(const escript::Data* data, int rank, const int* dimensions)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return 1;
   } else {
-     escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     return temp->isDataPointShapeEqual(rank, dimensions);
+     return data->isDataPointShapeEqual(rank, dimensions);
   }
 }
 
-int getNumDataPointsPerSample(struct escriptDataC* data) 
+int getNumDataPointsPerSample(const escript::Data* data) 
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return 0;
   } else {
-     escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     if (temp->isEmpty()) {
+     if (data->isEmpty()) {
         return 0;
      } else {
-          return (temp->getNumDataPointsPerSample());
+          return (data->getNumDataPointsPerSample());
      }
   }
 }
 
-int numSamplesEqual(struct escriptDataC* data, int numDataPointsPerSample,
+int numSamplesEqual(const escript::Data* data, int numDataPointsPerSample,
                     dim_t numSamples)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
      return 1;
   } else {
-     escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     return temp->numSamplesEqual(numDataPointsPerSample, numSamples);
+     return data->numSamplesEqual(numDataPointsPerSample, numSamples);
   }
 }
 
-int getDataPointRank(struct escriptDataC* data)
+int getDataPointRank(const escript::Data* data)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == (const escript::Data*)0) {
        return 0;
   } else {
-       escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-       return temp->getDataPointRank();
+       return data->getDataPointRank();
   }
 }
 
-int getDataPointShape(struct escriptDataC* data,int i)
+int getDataPointShape(const escript::Data* data,int i)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return 0;
   } else {
-     escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     int rank = temp->getDataPointRank();
+     int rank = data->getDataPointRank();
      if (i<0 || i>=rank) {
         return 1;
      } else {
-        const escript::DataTypes::ShapeType view=temp->getDataPointShape();
+        const escript::DataTypes::ShapeType& view=data->getDataPointShape();
         return view[i];
      }
   }
 }
 
-int getDataPointSize(struct escriptDataC* data)
+int getDataPointSize(const escript::Data* data)
 {
-  escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-  return temp->getDataPointSize();
+  return data->getDataPointSize();
 }
 
-int getLength(struct escriptDataC* data)
+int getLength(const escript::Data* data)
 {
-  escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-  return temp->getLength();
+  return data->getLength();
 }
 
-int isExpanded(struct escriptDataC* data)
+int isExpanded(const escript::Data* data)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return false;
   } else {
-     escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     if (temp->isEmpty()) {
+     if (data->isEmpty()) {
         return false;
      } else {
-        return temp->actsExpanded();
+        return data->actsExpanded();
      }
   }
 }
 
-int isEmpty(escriptDataC* data) 
+int isEmpty(const escript::Data* data) 
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return true;
   } else {
-      escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-      return temp->isEmpty();
+      return data->isEmpty();
   }
 }
 
-// The unusual (for me) ordering of __const here is because I'm not sure
-// whether gcc would try to interpret __const as a function attribute rather than
-// a modifier on the return value. Putting it here should remove any ambiguity
-// I have used const rather than __const in the cpp because only c++ will be reading the cpp.
-double const* getSampleDataRO(struct escriptDataC* data, int sampleNo)
+double const* getSampleDataRO(const escript::Data* data, int sampleNo)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return NULL;
   } else {
-      escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     if (temp->isEmpty()) {
+     if (data->isEmpty()) {
         return NULL;
      } else {
-        return temp->getSampleDataRO(sampleNo);
+        return data->getSampleDataRO(sampleNo);
      }
   }
 }
 
-double* getSampleDataRW(struct escriptDataC* data, int sampleNo)
+double* getSampleDataRW(escript::Data* data, int sampleNo)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return NULL;
   } else {
-      escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-     if (temp->isEmpty()) {
+     if (data->isEmpty()) {
         return NULL;
      } else {
-        return temp->getSampleDataRW(sampleNo);
+        return data->getSampleDataRW(sampleNo);
      }
   }
 }
 
-const double* getSampleDataROFast(struct escriptDataC* data, int sampleNo)
+const double* getSampleDataROFast(const escript::Data* data, int sampleNo)
 {
-  escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-  return temp->getSampleDataRO(sampleNo);
+  return data->getSampleDataRO(sampleNo);
 }
 
-double* getSampleDataRWFast(struct escriptDataC* data, int sampleNo)
+double* getSampleDataRWFast(escript::Data* data, int sampleNo)
 {
-  escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-  return temp->getSampleDataRW(sampleNo);
+  return data->getSampleDataRW(sampleNo);
 }
 
-double* getDataRW(escriptDataC* data)
+double* getDataRW(escript::Data* data)
 {
-  escript::Data* temp=(escript::Data*)(data->m_dataPtr);
-  if (temp->getNumSamples()>0)
+  
+  if (data->getNumSamples()>0)
   {
      requireWrite(data);
      return getSampleDataRWFast(data,0);
@@ -180,11 +164,11 @@ double* getDataRW(escriptDataC* data)
 }
 
 
-void requireWrite(escriptDataC* data)
+void requireWrite(escript::Data* data)
 {
-  if (data == (struct escriptDataC*)0) {
+  if (data == 0) {
        return;
   } else {
-      ((escript::Data*)(data->m_dataPtr))->requireWrite();
+      data->requireWrite();
   }
 }
diff --git a/escriptcore/src/DataC.h b/escriptcore/src/DataC.h
index b759e80..af132ca 100644
--- a/escriptcore/src/DataC.h
+++ b/escriptcore/src/DataC.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -19,26 +19,16 @@
 #define escript_DataC_20040611_H
 #include "system_dep.h"
 
-/**
-   \brief
-   Provide a wrapper around a Data object so Data may be accessed from C.
+#include "Data.h"
 
-   Description:
-   Provide a wrapper around a Data object so Data may be accessed from C.
 
-*/
-struct escriptDataC {
-  void* m_dataPtr;
-};
-
-typedef struct escriptDataC escriptDataC; 
 
 /**
    \brief
    Return the function space type code.
    \param data Input - C wrapper for Data.
 */
-ESCRIPT_DLL_API int getFunctionSpaceType(escriptDataC* data);
+ESCRIPT_DLL_API int getFunctionSpaceType(const escript::Data* data);
 
 /**
    \brief
@@ -62,7 +52,7 @@ ESCRIPT_DLL_API int getFunctionSpaceType(escriptDataC* data);
    Returns the true if the data are empty or data is NULL.
    \param data Input - C wrapper for Data.
 */
-ESCRIPT_DLL_API int isEmpty(escriptDataC* data);
+ESCRIPT_DLL_API int isEmpty(const escript::Data* data);
 
 /**
    \brief
@@ -71,7 +61,7 @@ ESCRIPT_DLL_API int isEmpty(escriptDataC* data);
    \param rank Input - number of dimensions.
    \param dimensions Input - 
 */
-ESCRIPT_DLL_API int isDataPointShapeEqual(escriptDataC* data, int rank, const int* dimensions);
+ESCRIPT_DLL_API int isDataPointShapeEqual(const escript::Data* data, int rank, const int* dimensions);
 /**
    \brief
    Return true if the number of data points per sample and the number 
@@ -81,7 +71,7 @@ ESCRIPT_DLL_API int isDataPointShapeEqual(escriptDataC* data, int rank, const in
    \param numDataPointsPerSample Input - number of data points per sample
    \param numSamples Input - number of samples
 */
-ESCRIPT_DLL_API int numSamplesEqual(escriptDataC* data, int numDataPointsPerSample,
+ESCRIPT_DLL_API int numSamplesEqual(const escript::Data* data, int numDataPointsPerSample,
 		    dim_t numSamples);
 
 /**
@@ -89,14 +79,14 @@ ESCRIPT_DLL_API int numSamplesEqual(escriptDataC* data, int numDataPointsPerSamp
    Returns the number of data points per sample
    \param data Input - C wrapper for Data.
 */
-ESCRIPT_DLL_API int getNumDataPointsPerSample(escriptDataC* data);
+ESCRIPT_DLL_API int getNumDataPointsPerSample(const escript::Data* data);
 
 /**
    \brief
    Returns the rank of the point data for the data. 
    \param data Input - C wrapper for Data.
 */
-ESCRIPT_DLL_API int getDataPointRank(escriptDataC* data);
+ESCRIPT_DLL_API int getDataPointRank(const escript::Data* data);
 
 /**
    \brief
@@ -104,24 +94,14 @@ ESCRIPT_DLL_API int getDataPointRank(escriptDataC* data);
    \param data Input - C wrapper for Data.
    \param i Input - index of shape component.
 */
-ESCRIPT_DLL_API int getDataPointShape(escriptDataC* data, int i);
+ESCRIPT_DLL_API int getDataPointShape(const escript::Data* data, int i);
 
 /**
    \brief
    Return the number of doubles needed for each data point.
    \param data Input - C wrapper for Data.
 */
-ESCRIPT_DLL_API int getDataPointSize(escriptDataC* data);
-
-/*
-   \brief
-   Return the number of doubles stored for the Data object.
-   Argument data may be NULL, in which case 0 is returnd.
-   \param data Input - C wrapper for Data.
-
-This function has been removed because it does not make sense for LazyData
-*/
-/*ESCRIPT_DLL_API int getLength(escriptDataC* data);*/
+ESCRIPT_DLL_API int getDataPointSize(const escript::Data* data);
 
 /**
    \brief
@@ -131,7 +111,7 @@ This function has been removed because it does not make sense for LazyData
    \param data Input - C wrapper for Data.
    \return true if data is expanded or the data is lazy but would resolve to expanded. False otherwise.
 */
-ESCRIPT_DLL_API int isExpanded(escriptDataC* data);
+ESCRIPT_DLL_API int isExpanded(const escript::Data* data);
 
 /**
    \brief
@@ -142,11 +122,11 @@ ESCRIPT_DLL_API int isExpanded(escriptDataC* data);
   \param sampleNo Input - The sample number.
 
 */
-ESCRIPT_DLL_API double __const * getSampleDataRO(escriptDataC* data, int sampleNo);
+ESCRIPT_DLL_API double const * getSampleDataRO(const escript::Data* data, int sampleNo);
 /* Placement of __const might be important. See .cpp */
 
 
-ESCRIPT_DLL_API double* getSampleDataRW(escriptDataC* data, int sampleNo);
+ESCRIPT_DLL_API double* getSampleDataRW(escript::Data* data, int sampleNo);
 
 
 /**
@@ -157,7 +137,7 @@ ESCRIPT_DLL_API double* getSampleDataRW(escriptDataC* data, int sampleNo);
   \param sampleNo Input - The sample number.
 
 */
-ESCRIPT_DLL_API double __const* getSampleDataROFast(escriptDataC* data, int sampleNo);
+ESCRIPT_DLL_API double const* getSampleDataROFast(const escript::Data* data, int sampleNo);
 
 /**
    \brief
@@ -166,7 +146,7 @@ ESCRIPT_DLL_API double __const* getSampleDataROFast(escriptDataC* data, int samp
   \param data Input - C wrapper for Data.
   \param sampleNo Input - The sample number.
 */
-ESCRIPT_DLL_API double* getSampleDataRWFast(escriptDataC* data, int sampleNo);
+ESCRIPT_DLL_API double* getSampleDataRWFast(escript::Data* data, int sampleNo);
 
 
 /**
@@ -177,7 +157,7 @@ ESCRIPT_DLL_API double* getSampleDataRWFast(escriptDataC* data, int sampleNo);
    \warning Please do not use this in new code.
   \param data Input - C wrapper for Data.
 */
-ESCRIPT_DLL_API double* getDataRW(escriptDataC* data);
+ESCRIPT_DLL_API double* getDataRW(escript::Data* data);
 
 
 /**
@@ -187,6 +167,6 @@ ESCRIPT_DLL_API double* getDataRW(escriptDataC* data);
    Do not create new Data objects based on this one between this call and 
    writing to the object.
 */
-ESCRIPT_DLL_API void requireWrite(escriptDataC* data);
+ESCRIPT_DLL_API void requireWrite(escript::Data* data);
 
 #endif
diff --git a/escriptcore/src/DataConstant.cpp b/escriptcore/src/DataConstant.cpp
index 1be01c2..1bcf585 100644
--- a/escriptcore/src/DataConstant.cpp
+++ b/escriptcore/src/DataConstant.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "Data.h"
 #include "DataConstant.h"
diff --git a/escriptcore/src/DataConstant.h b/escriptcore/src/DataConstant.h
index 6b964b2..8402260 100644
--- a/escriptcore/src/DataConstant.h
+++ b/escriptcore/src/DataConstant.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataEmpty.cpp b/escriptcore/src/DataEmpty.cpp
index fb3953d..d19df83 100644
--- a/escriptcore/src/DataEmpty.cpp
+++ b/escriptcore/src/DataEmpty.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "DataEmpty.h"
 #include "DataException.h"
diff --git a/escriptcore/src/DataEmpty.h b/escriptcore/src/DataEmpty.h
index 9e039f2..d048209 100644
--- a/escriptcore/src/DataEmpty.h
+++ b/escriptcore/src/DataEmpty.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataException.cpp b/escriptcore/src/DataException.cpp
index e6f9767..bca2211 100644
--- a/escriptcore/src/DataException.cpp
+++ b/escriptcore/src/DataException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataException.h b/escriptcore/src/DataException.h
index 6706ea8..d5922cc 100644
--- a/escriptcore/src/DataException.h
+++ b/escriptcore/src/DataException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataExpanded.cpp b/escriptcore/src/DataExpanded.cpp
index 4674a96..4382b53 100644
--- a/escriptcore/src/DataExpanded.cpp
+++ b/escriptcore/src/DataExpanded.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "Data.h"
 #include "DataExpanded.h"
diff --git a/escriptcore/src/DataExpanded.h b/escriptcore/src/DataExpanded.h
index 2e828e3..0dfaadf 100644
--- a/escriptcore/src/DataExpanded.h
+++ b/escriptcore/src/DataExpanded.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataFactory.cpp b/escriptcore/src/DataFactory.cpp
index 155bf4e..027f8e9 100644
--- a/escriptcore/src/DataFactory.cpp
+++ b/escriptcore/src/DataFactory.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataFactory.h"
 #include "esysUtils/Esys_MPI.h"
diff --git a/escriptcore/src/DataFactory.h b/escriptcore/src/DataFactory.h
index 819a5b9..7175887 100644
--- a/escriptcore/src/DataFactory.h
+++ b/escriptcore/src/DataFactory.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -18,17 +18,6 @@
 #if !defined escript_DataFactory_20040721_H
 #define escript_DataFactory_20040721_H
 
-#ifdef BADPYTHONMACROS
-// This hack is required for BSD/OSX builds with python 2.7
-// (and possibly others).  It must be the first include.
-// From bug reports online it seems that python redefines
-// some c macros that are functions in c++.
-// c++ doesn't like that!
-#include <Python.h>
-#undef BADPYTHONMACROS
-#endif
-
-
 #include "system_dep.h"
 
 #include "AbstractDomain.h"
diff --git a/escriptcore/src/DataLazy.cpp b/escriptcore/src/DataLazy.cpp
index 4123b00..d2bea59 100644
--- a/escriptcore/src/DataLazy.cpp
+++ b/escriptcore/src/DataLazy.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "DataLazy.h"
 #include "esysUtils/Esys_MPI.h"
diff --git a/escriptcore/src/DataLazy.h b/escriptcore/src/DataLazy.h
index d5880e9..e121cb9 100644
--- a/escriptcore/src/DataLazy.h
+++ b/escriptcore/src/DataLazy.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataMaths.cpp b/escriptcore/src/DataMaths.cpp
index c5ab643..b3fc07a 100644
--- a/escriptcore/src/DataMaths.cpp
+++ b/escriptcore/src/DataMaths.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "DataTypes.h"
 #include "DataMaths.h"
diff --git a/escriptcore/src/DataMaths.h b/escriptcore/src/DataMaths.h
index 707c175..8a6aeaf 100644
--- a/escriptcore/src/DataMaths.h
+++ b/escriptcore/src/DataMaths.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataReady.cpp b/escriptcore/src/DataReady.cpp
index 96653e1..8d6e297 100644
--- a/escriptcore/src/DataReady.cpp
+++ b/escriptcore/src/DataReady.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "DataReady.h"
 
 namespace escript
diff --git a/escriptcore/src/DataReady.h b/escriptcore/src/DataReady.h
index b124c87..9cb81be 100644
--- a/escriptcore/src/DataReady.h
+++ b/escriptcore/src/DataReady.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataTagged.cpp b/escriptcore/src/DataTagged.cpp
index b177ba3..1aff038 100644
--- a/escriptcore/src/DataTagged.cpp
+++ b/escriptcore/src/DataTagged.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "Data.h"
 #include "DataTagged.h"
diff --git a/escriptcore/src/DataTagged.h b/escriptcore/src/DataTagged.h
index 268f381..22264c2 100644
--- a/escriptcore/src/DataTagged.h
+++ b/escriptcore/src/DataTagged.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataTypes.cpp b/escriptcore/src/DataTypes.cpp
index 2e641ab..ebc4fb9 100644
--- a/escriptcore/src/DataTypes.cpp
+++ b/escriptcore/src/DataTypes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataTypes.h"
 #include <sstream>
diff --git a/escriptcore/src/DataTypes.h b/escriptcore/src/DataTypes.h
index a464360..6b5db83 100644
--- a/escriptcore/src/DataTypes.h
+++ b/escriptcore/src/DataTypes.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DataVector.cpp b/escriptcore/src/DataVector.cpp
index d7480d8..406a714 100644
--- a/escriptcore/src/DataVector.cpp
+++ b/escriptcore/src/DataVector.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataVector.h"
 
diff --git a/escriptcore/src/DataVector.h b/escriptcore/src/DataVector.h
index 0d72738..e4f13d8 100644
--- a/escriptcore/src/DataVector.h
+++ b/escriptcore/src/DataVector.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Dodgy.cpp b/escriptcore/src/Dodgy.cpp
index c7273bb..c77eab9 100644
--- a/escriptcore/src/Dodgy.cpp
+++ b/escriptcore/src/Dodgy.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2009-2014 by University of Queensland
+* Copyright (c) 2009-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Dodgy.h b/escriptcore/src/Dodgy.h
index a2873ac..fcdd374 100644
--- a/escriptcore/src/Dodgy.h
+++ b/escriptcore/src/Dodgy.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2009-2014 by University of Queensland
+* Copyright (c) 2009-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DomainException.cpp b/escriptcore/src/DomainException.cpp
index 7589fca..633012c 100644
--- a/escriptcore/src/DomainException.cpp
+++ b/escriptcore/src/DomainException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/DomainException.h b/escriptcore/src/DomainException.h
index d4c84b0..b9687e0 100644
--- a/escriptcore/src/DomainException.h
+++ b/escriptcore/src/DomainException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/EscriptParams.cpp b/escriptcore/src/EscriptParams.cpp
index 722d72b..ccd1843 100644
--- a/escriptcore/src/EscriptParams.cpp
+++ b/escriptcore/src/EscriptParams.cpp
@@ -2,7 +2,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -15,6 +15,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "EscriptParams.h"
 #include <cstring>
 #include <boost/python/tuple.hpp>
diff --git a/escriptcore/src/EscriptParams.h b/escriptcore/src/EscriptParams.h
index 1cba103..6c490d5 100644
--- a/escriptcore/src/EscriptParams.h
+++ b/escriptcore/src/EscriptParams.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/FunctionSpace.cpp b/escriptcore/src/FunctionSpace.cpp
index 155561a..48d35ce 100644
--- a/escriptcore/src/FunctionSpace.cpp
+++ b/escriptcore/src/FunctionSpace.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "FunctionSpace.h" 
 #include "FunctionSpaceException.h"
diff --git a/escriptcore/src/FunctionSpace.h b/escriptcore/src/FunctionSpace.h
index 29729e9..1c94d63 100644
--- a/escriptcore/src/FunctionSpace.h
+++ b/escriptcore/src/FunctionSpace.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/FunctionSpaceException.cpp b/escriptcore/src/FunctionSpaceException.cpp
index 79661ac..d741d59 100644
--- a/escriptcore/src/FunctionSpaceException.cpp
+++ b/escriptcore/src/FunctionSpaceException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/FunctionSpaceException.h b/escriptcore/src/FunctionSpaceException.h
index 3ee943e..6ab4f20 100644
--- a/escriptcore/src/FunctionSpaceException.h
+++ b/escriptcore/src/FunctionSpaceException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/FunctionSpaceFactory.cpp b/escriptcore/src/FunctionSpaceFactory.cpp
index cecc28c..e959a81 100644
--- a/escriptcore/src/FunctionSpaceFactory.cpp
+++ b/escriptcore/src/FunctionSpaceFactory.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "FunctionSpaceFactory.h"
 #include "AbstractContinuousDomain.h"
diff --git a/escriptcore/src/FunctionSpaceFactory.h b/escriptcore/src/FunctionSpaceFactory.h
index 8c225ef..d6b9487 100644
--- a/escriptcore/src/FunctionSpaceFactory.h
+++ b/escriptcore/src/FunctionSpaceFactory.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/LapackInverseHelper.cpp b/escriptcore/src/LapackInverseHelper.cpp
index 7ef411f..6f961c8 100644
--- a/escriptcore/src/LapackInverseHelper.cpp
+++ b/escriptcore/src/LapackInverseHelper.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2009-2014 by University of Queensland
+* Copyright (c) 2009-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/LapackInverseHelper.h b/escriptcore/src/LapackInverseHelper.h
index 28212a5..95c4161 100644
--- a/escriptcore/src/LapackInverseHelper.h
+++ b/escriptcore/src/LapackInverseHelper.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2009-2014 by University of Queensland
+* Copyright (c) 2009-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/LocalOps.h b/escriptcore/src/LocalOps.h
index 2090fb0..baa2d02 100644
--- a/escriptcore/src/LocalOps.h
+++ b/escriptcore/src/LocalOps.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -17,11 +17,7 @@
 
 #if !defined escript_LocalOps_H
 #define escript_LocalOps_H
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-#   include <mathimf.h>
-#else
-#   include <cmath>
-#endif
+#include <cmath>
 #ifndef M_PI
 #   define M_PI           3.14159265358979323846  /* pi */
 #endif
diff --git a/escriptcore/src/Reducer.cpp b/escriptcore/src/MPIDataReducer.cpp
similarity index 90%
rename from escriptcore/src/Reducer.cpp
rename to escriptcore/src/MPIDataReducer.cpp
index bdfd819..480d7dc 100644
--- a/escriptcore/src/Reducer.cpp
+++ b/escriptcore/src/MPIDataReducer.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,11 +13,16 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <sstream>
+#include <limits>
 #include <boost/python/extract.hpp>
 #include <boost/scoped_array.hpp>
 
-#include "Reducer.h"
+#include "MPIDataReducer.h"
 #include "SplitWorldException.h"
 
 using namespace boost::python;
@@ -54,18 +59,8 @@ void combineData(Data& d1, const Data& d2, MPI_Op op)
     }
 }
 
-#ifdef ESYS_MPI
-const int PARAMTAG=120567;	// arbitrary value
-#endif
-}
-
-bool AbstractReducer::hasValue()
-{
-    return valueadded;
 }
 
-
-
 MPIDataReducer::MPIDataReducer(MPI_Op op)
   : reduceop(op)
 {
@@ -73,6 +68,7 @@ MPIDataReducer::MPIDataReducer(MPI_Op op)
     if (op==MPI_SUM)
     {
 	// deliberately left blank
+	throw SplitWorldException("Unsupported MPI_Op");
     }
     else
     {
@@ -80,11 +76,17 @@ MPIDataReducer::MPIDataReducer(MPI_Op op)
     }
 }
 
+
 void MPIDataReducer::setDomain(escript::Domain_ptr d)
 {
     dom=d;
 }
 
+std::string MPIDataReducer::description()
+{
+    std::string op="SUM";
+    return "Reducer("+op+") for Data objects"; 
+}
 
 bool MPIDataReducer::valueCompatible(boost::python::object v)
 {
@@ -186,8 +188,12 @@ bool MPIDataReducer::checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::st
 
 // By the time this function is called, we know that all the values 
 // are compatible
-bool MPIDataReducer::reduceRemoteValues(esysUtils::JMPI& mpi_info)
+bool MPIDataReducer::reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active)
 {
+    if (!active)
+    {
+	return false;	// shutting down this option until I implement it
+    }
 #ifdef ESYS_MPI
     DataTypes::ValueType& vr=value.getExpandedVectorReference();
     Data result(0, value.getDataPointShape(), value.getFunctionSpace(), true);
@@ -329,3 +335,21 @@ bool MPIDataReducer::sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUti
 #endif      
       return true;
 }
+
+boost::python::object MPIDataReducer::getPyObj()
+{
+    throw SplitWorldException("getPyObj Not implemented yet.");
+}
+
+
+	// send from proc 0 in the communicator to all others
+bool MPIDataReducer::groupSend(MPI_Comm& com)
+{
+    throw SplitWorldException("groupSend Not implemented yet.");
+}
+
+bool MPIDataReducer::groupReduce(MPI_Comm& com, char mystate)
+{
+    throw SplitWorldException("groupReduce Not implemented yet.");
+}
+
diff --git a/escriptcore/src/MPIDataReducer.h b/escriptcore/src/MPIDataReducer.h
new file mode 100644
index 0000000..9487a3e
--- /dev/null
+++ b/escriptcore/src/MPIDataReducer.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+*
+* Copyright (c) 2014-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#ifndef __ESCRIPT_DATAREDUCER_H__
+#define __ESCRIPT_DATAREDUCER_H__
+
+#include "esysUtils/Esys_MPI.h"
+#include "escript/Data.h"
+#include <boost/shared_ptr.hpp>
+#include "AbstractReducer.h"
+namespace escript
+{
+
+// Reduces using pointwise MPI operations
+class MPIDataReducer : public AbstractReducer
+{
+public:
+    MPIDataReducer(MPI_Op op);
+    ~MPIDataReducer(){};
+    
+        // This is not a constructor parameter because 
+        // if these are created outside the subworld, they won't have
+        // access to a domain yet.
+        // I also want SplitWorld to be able to set this
+    void setDomain(escript::Domain_ptr d);
+    bool valueCompatible(boost::python::object v);
+    bool reduceLocalValue(boost::python::object v, std::string& errstring);
+    void reset();
+    bool checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring);
+    
+    void getCompatibilityInfo(std::vector<unsigned>& params);
+    
+      // talk to corresponding processes in other subworlds
+    bool reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active);
+    
+      // human readable description
+    std::string description();
+    
+	// Get a value for this variable from another process
+	// This is not a reduction and will replace any existing value
+    bool recvFrom(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo);
+
+	// Send a value to this variable to another process
+	// This is not a reduction and will replace any existing value    
+    bool sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUtils::JMPI& mpiinfo);    
+    virtual boost::python::object getPyObj();
+
+	// send from proc 0 in the communicator to all others
+    bool groupSend(MPI_Comm& com);
+    
+	// reduction with some procs submitting identity values
+    bool groupReduce(MPI_Comm& com, char mystate);    
+    
+private:    
+    escript::Data value;
+    escript::const_Domain_ptr dom;
+    MPI_Op reduceop;
+};
+
+Reducer_ptr makeDataReducer(std::string type);
+
+}
+
+#endif // __ESCRIPT_DATAREDUCER_H__
+
diff --git a/escriptcore/src/MPIScalarReducer.cpp b/escriptcore/src/MPIScalarReducer.cpp
new file mode 100644
index 0000000..f3840da
--- /dev/null
+++ b/escriptcore/src/MPIScalarReducer.cpp
@@ -0,0 +1,271 @@
+/*****************************************************************************
+*
+* Copyright (c) 2014-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
+#include <sstream>
+#include <limits>
+#include <boost/python/extract.hpp>
+#include <boost/scoped_array.hpp>
+
+#include "MPIScalarReducer.h"
+#include "SplitWorldException.h"
+
+using namespace boost::python;
+using namespace escript;
+
+
+namespace escript
+{
+
+Reducer_ptr makeScalarReducer(std::string type)
+{
+    MPI_Op op;
+    if (type=="SUM")
+    {
+	op=MPI_SUM;
+    }
+    else if (type=="MAX")
+    {
+	op=MPI_MAX;
+    }
+    else if (type=="MIN")
+    {
+	op=MPI_MIN;
+    }
+    else
+    {
+	throw SplitWorldException("Unsupported operation for makeScalarReducer.");
+    }
+    MPIScalarReducer* m=new MPIScalarReducer(op);
+    return Reducer_ptr(m);    
+}
+
+
+}
+
+namespace
+{
+
+void combineDouble(double& d1, const double d2, MPI_Op op)
+{
+    if (op==MPI_SUM)
+    {
+	d1+=d2;
+    }  
+    else if (op==MPI_MAX)
+    {
+	d1=(d2>d1)?d2:d1;
+    }
+    else if (op==MPI_MIN)
+    {
+	d1=(d2<d1)?d2:d1;      
+    }    
+}
+}
+
+
+MPIScalarReducer::MPIScalarReducer(MPI_Op op)
+  : reduceop(op)
+{
+    valueadded=false;
+    if (op==MPI_SUM)	// why not switch? because we don't know MPI_Op is scalar
+    {
+	identity=0;
+    }
+    else if (op==MPI_MAX)
+    {
+	identity=std::numeric_limits<double>::min();
+    }
+    else if (op==MPI_MIN)
+    {
+	identity=std::numeric_limits<double>::max();
+    }
+    else      
+    {
+	throw SplitWorldException("Unsupported MPI_Op");
+    }
+}
+
+void MPIScalarReducer::setDomain(escript::Domain_ptr d)
+{
+    // deliberately left blank
+}
+
+std::string MPIScalarReducer::description()
+{
+    std::string op;
+    if (reduceop==MPI_SUM)
+    {
+	op="SUM";
+    }
+    else if (reduceop==MPI_MAX)
+    {
+	op="MAX";
+    } 
+    else if (reduceop==MPI_MIN)
+    {
+	op="MIN";
+    }
+    else
+    {
+	throw SplitWorldException("Unsupported MPI reduction operation");
+    }
+    return "Reducer("+op+") for double scalars"; 
+}
+
+bool MPIScalarReducer::valueCompatible(boost::python::object v)
+{
+    extract<double> ex(v);
+    if (!ex.check())
+    {
+	return false;
+    }
+    return true;
+}
+
+
+bool MPIScalarReducer::reduceLocalValue(boost::python::object v, std::string& errstring)
+{
+    extract<double> ex(v);
+    if (!ex.check())
+    {
+	errstring="reduceLocalValue: expected double value. Got something else.";
+	return false;
+    }
+    if (!valueadded)	// first value so answer becomes this one
+    {
+	value=ex();
+	valueadded=true;
+    }
+    else
+    {
+	combineDouble(value, ex(), reduceop);
+    }
+    return true;
+}
+
+void MPIScalarReducer::reset()
+{
+    valueadded=false;
+    value=0;
+}
+
+bool MPIScalarReducer::checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring)
+{
+    return true;
+}
+
+// By the time this function is called, we know that all the values 
+// are compatible
+bool MPIScalarReducer::reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active)
+{
+#ifdef ESYS_MPI
+    if (!active)
+    {
+        value=identity;
+    }
+std::cout << "Value in " << value << std::endl;    
+    if (MPI_Allreduce(&value, &value, 1, MPI_DOUBLE, reduceop, mpi_info->comm)!=MPI_SUCCESS)
+    {
+	return false;
+    }
+std::cout << "Value out " << value << std::endl;    
+    return true;
+#else
+    return true;
+#endif
+}
+
+// populate a vector of ints with enough information to ensure two values are compatible
+// or to construct a container for incomming data
+// Format for this:
+//  [0]    Type of Data:  {0 : error,  1: DataEmpty, 10: constant, 11:tagged, 12:expanded}
+//  [1]    Functionspace type code
+//  [2]    Only used for tagged --- gives the number of tags (which exist in the data object)
+//  [3..6] Components of the shape  
+void MPIScalarReducer::getCompatibilityInfo(std::vector<unsigned>& params)
+{
+    params.resize(1);	// in case someone tries to do something with it
+}
+
+
+	// Get a value for this variable from another process
+	// This is not a reduction and will replace any existing value
+bool MPIScalarReducer::recvFrom(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo)
+{
+#ifdef ESYS_MPI  
+    MPI_Status stat;
+    if (MPI_Recv(&value, 1, MPI_DOUBLE, source, PARAMTAG, mpiinfo->comm, &stat)!=MPI_SUCCESS)
+    {
+	return false;
+    }
+#endif    
+    return true;
+}
+
+	// Send a value to this variable to another process
+	// This is not a reduction and will replace any existing value    
+bool MPIScalarReducer::sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUtils::JMPI& mpiinfo)
+{
+#ifdef ESYS_MPI  
+      if (MPI_Send(&value, 1, MPI_DOUBLE, target, PARAMTAG, mpiinfo->comm)!=MPI_SUCCESS)
+      {
+	  return false;
+      }
+#endif      
+      return true;
+}
+
+double MPIScalarReducer::getDouble()
+{
+    return value;
+}
+
+
+boost::python::object MPIScalarReducer::getPyObj()
+{
+    boost::python::object o(value);
+    return o;
+}
+
+#ifdef ESYS_MPI
+
+	// send from proc 0 in the communicator to all others
+bool MPIScalarReducer::groupSend(MPI_Comm& com)
+{
+    if (MPI_Bcast(&value, 1, MPI_DOUBLE, 0, com)==MPI_SUCCESS)
+    {
+	valueadded=true;
+	return true;
+    }
+    return false;
+}
+
+bool MPIScalarReducer::groupReduce(MPI_Comm& com, char mystate)
+{
+    double answer=0;
+    if (MPI_Allreduce((mystate==reducerstatus::NEW)?&value:&identity, &answer, 1, MPI_DOUBLE, reduceop, com)==MPI_SUCCESS)
+    {
+	value=answer;
+	valueadded=true;
+	return true;
+    }
+    return false;
+}
+
+#endif
diff --git a/escriptcore/src/MPIScalarReducer.h b/escriptcore/src/MPIScalarReducer.h
new file mode 100644
index 0000000..d63c5a0
--- /dev/null
+++ b/escriptcore/src/MPIScalarReducer.h
@@ -0,0 +1,80 @@
+/*****************************************************************************
+*
+* Copyright (c) 2014-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#ifndef __ESCRIPT_SCALARREDUCER_H__
+#define __ESCRIPT_SCALARREDUCER_H__
+
+#include "esysUtils/Esys_MPI.h"
+#include "escript/Data.h"
+#include <boost/shared_ptr.hpp>
+#include "AbstractReducer.h"
+namespace escript
+{
+
+// Reduces using pointwise MPI operations on double
+class MPIScalarReducer : public AbstractReducer
+{
+public:
+    MPIScalarReducer(MPI_Op op);
+    ~MPIScalarReducer(){};
+    
+        // This is not a constructor parameter because 
+        // if these are created outside the subworld, they won't have
+        // access to a domain yet.
+        // I also want SplitWorld to be able to set this
+    void setDomain(escript::Domain_ptr d);
+    bool valueCompatible(boost::python::object v);
+    bool reduceLocalValue(boost::python::object v, std::string& errstring);
+    void reset();
+    bool checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring);
+    
+    void getCompatibilityInfo(std::vector<unsigned>& params);
+    
+      // talk to corresponding processes in other subworlds
+    bool reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active);
+    
+      // human readable description
+    std::string description();
+    
+	// Get a value for this variable from another process
+	// This is not a reduction and will replace any existing value
+    bool recvFrom(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo);
+
+	// Send a value to this variable to another process
+	// This is not a reduction and will replace any existing value    
+    bool sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUtils::JMPI& mpiinfo);    
+    double getDouble();
+    virtual boost::python::object getPyObj(); 
+    
+    	// send from proc 0 in the communicator to all others
+    bool groupSend(MPI_Comm& com);
+    
+	// reduction with some procs submitting identity values
+    bool groupReduce(MPI_Comm& com, char mystate);
+    
+private:    
+    double value;
+    MPI_Op reduceop;
+    double identity;
+};
+
+
+Reducer_ptr makeScalarReducer(std::string type);
+
+
+}
+
+#endif // __ESCRIPT_SCALARREDUCER_H__
+
diff --git a/escriptcore/src/NonReducedVariable.cpp b/escriptcore/src/NonReducedVariable.cpp
new file mode 100644
index 0000000..80a2dc0
--- /dev/null
+++ b/escriptcore/src/NonReducedVariable.cpp
@@ -0,0 +1,121 @@
+/*****************************************************************************
+*
+* Copyright (c) 2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
+#include "NonReducedVariable.h"
+#include "SplitWorldException.h"
+
+using namespace escript;
+
+NonReducedVariable::NonReducedVariable()
+{
+    valueadded=false;
+}
+
+NonReducedVariable::~NonReducedVariable()
+{
+}
+
+void NonReducedVariable::setDomain(escript::Domain_ptr d)
+{
+	
+}
+
+
+// SInce there is no remote transfer, we don't need to check this
+bool NonReducedVariable::valueCompatible(boost::python::object v)
+{
+    return true;
+}
+
+// Any new export, replaces the old value
+bool NonReducedVariable::reduceLocalValue(boost::python::object v, std::string& errstring)
+{
+    value=v;
+    valueadded=true;
+    return true;
+}
+
+void NonReducedVariable::reset()
+{
+    value=boost::python::object();
+    valueadded=false;
+}
+
+// Since we aren't actually don't a check here, this call won't function
+// as a barrier like other implementations of this method
+bool NonReducedVariable::checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring)
+{
+    return true;
+}
+
+void NonReducedVariable::getCompatibilityInfo(std::vector<unsigned>& params)
+{
+    // empty
+}
+
+bool NonReducedVariable::reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active)
+{
+    return true;
+}
+
+std::string NonReducedVariable::description()
+{
+    return "Non-Reduced Variable.";
+}
+
+bool NonReducedVariable::recvFrom(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo)
+{
+    return true;
+}
+
+bool NonReducedVariable::sendTo(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo)
+{
+    return true;
+}
+
+double NonReducedVariable::getDouble()
+{
+    throw SplitWorldException("No double value from this type.");
+}
+
+boost::python::object NonReducedVariable::getPyObj()
+{
+    return value;
+}
+
+bool NonReducedVariable::groupSend(MPI_Comm& com)
+{
+    return true;
+}
+
+bool NonReducedVariable::groupReduce(MPI_Comm& com, char mystate)
+{
+    return true;
+}
+
+namespace escript
+{
+Reducer_ptr makeNonReducedVariable()
+{
+    NonReducedVariable* m=new NonReducedVariable();
+    return Reducer_ptr(m);
+
+}
+
+}
diff --git a/escriptcore/src/NonReducedVariable.h b/escriptcore/src/NonReducedVariable.h
new file mode 100644
index 0000000..b6a8fd7
--- /dev/null
+++ b/escriptcore/src/NonReducedVariable.h
@@ -0,0 +1,80 @@
+/*****************************************************************************
+*
+* Copyright (c) 2014-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#ifndef __ESCRIPT_NONREDUCEDVARIABLE_H__
+#define __ESCRIPT_NONREDUCEDVARIABLE_H__
+
+#include "esysUtils/Esys_MPI.h"
+#include "escript/Data.h"
+#include <boost/shared_ptr.hpp>
+#include "AbstractReducer.h"
+namespace escript
+{
+
+// plugs into the import/export mechanism but stays on the 
+// subworld it was created by (no actual reduction takes place
+class NonReducedVariable : public AbstractReducer
+{
+public:
+    NonReducedVariable();
+    ~NonReducedVariable();
+    
+        // This is not a constructor parameter because 
+        // if these are created outside the subworld, they won't have
+        // access to a domain yet.
+        // I also want SplitWorld to be able to set this
+    void setDomain(escript::Domain_ptr d);
+    bool valueCompatible(boost::python::object v);
+    bool reduceLocalValue(boost::python::object v, std::string& errstring);
+    void reset();
+    bool checkRemoteCompatibility(esysUtils::JMPI& mpi_info, std::string& errstring);
+    
+    void getCompatibilityInfo(std::vector<unsigned>& params);
+    
+      // talk to corresponding processes in other subworlds
+    bool reduceRemoteValues(esysUtils::JMPI& mpi_info, bool active);
+    
+      // human readable description
+    std::string description();
+    
+	// Get a value for this variable from another process
+	// This is not a reduction and will replace any existing value
+    bool recvFrom(Esys_MPI_rank localid, Esys_MPI_rank source, esysUtils::JMPI& mpiinfo);
+
+	// Send a value to this variable to another process
+	// This is not a reduction and will replace any existing value    
+    bool sendTo(Esys_MPI_rank localid, Esys_MPI_rank target, esysUtils::JMPI& mpiinfo);    
+    double getDouble();
+    virtual boost::python::object getPyObj(); 
+    
+    	// send from proc 0 in the communicator to all others
+    bool groupSend(MPI_Comm& com);
+    
+	// reduction with some procs submitting identity values
+    bool groupReduce(MPI_Comm& com, char mystate);
+    
+private:    
+    boost::python::object value;
+    boost::python::object identity;
+};
+
+
+Reducer_ptr makeNonReducedVariable();
+
+
+}
+
+#endif // __ESCRIPT_NONREDUCEDVARIABLE_H__
+
diff --git a/escriptcore/src/NullDomain.cpp b/escriptcore/src/NullDomain.cpp
index bd0001d..5809538 100644
--- a/escriptcore/src/NullDomain.cpp
+++ b/escriptcore/src/NullDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DomainException.h"
 #include "NullDomain.h" 
@@ -26,8 +29,8 @@ int defaultList[2]={0,1}; // an array to return in borrowListOfTagsInUse();
 }
 
 // Null domains only support 1 functionspace type.
-// The choice of =1 as the value is arbitrary
-int NullDomain::NullDomainFS = 1;
+// The choice of -7 as the value is to prevent collision with other domain enums
+int NullDomain::NullDomainFS = -7;
 dim_t NullDomain::referenceID = dim_t(10); // arbitrary
 
 std::string NullDomain::getDescription() const 
diff --git a/escriptcore/src/NullDomain.h b/escriptcore/src/NullDomain.h
index 8f21625..f7e9b9c 100644
--- a/escriptcore/src/NullDomain.h
+++ b/escriptcore/src/NullDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Pointers.h b/escriptcore/src/Pointers.h
index 2813691..3060506 100644
--- a/escriptcore/src/Pointers.h
+++ b/escriptcore/src/Pointers.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SConscript b/escriptcore/src/SConscript
index d999088..6e1faca 100644
--- a/escriptcore/src/SConscript
+++ b/escriptcore/src/SConscript
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -27,6 +27,7 @@ del py_wrapper_local_env['SHLIBPREFIX']
 sources = """
     AbstractContinuousDomain.cpp
     AbstractDomain.cpp
+    AbstractReducer.cpp
     AbstractSystemMatrix.cpp
     AbstractTransportProblem.cpp
     Data.cpp
@@ -50,8 +51,10 @@ sources = """
     FunctionSpaceException.cpp
     FunctionSpaceFactory.cpp
     LapackInverseHelper.cpp
+    NonReducedVariable.cpp
     NullDomain.cpp
-    Reducer.cpp
+    MPIDataReducer.cpp
+    MPIScalarReducer.cpp
     SplitWorld.cpp
     SplitWorldException.cpp
     SubWorld.cpp
@@ -68,6 +71,7 @@ sources = """
 headers = """
     AbstractContinuousDomain.h
     AbstractDomain.h
+    AbstractReducer.h
     AbstractSystemMatrix.h
     AbstractTransportProblem.h
     BinaryOp.h
@@ -95,9 +99,11 @@ headers = """
     FunctionSpaceFactory.h
     LapackInverseHelper.h
     LocalOps.h
+    NonReducedVariable.h
     NullDomain.h
+    MPIDataReducer.h
+    MPIScalarReducer.h
     Pointers.h
-    Reducer.h
     SplitWorld.h
     SplitWorldException.h
     SubWorld.h
diff --git a/escriptcore/src/SolverOptions.cpp b/escriptcore/src/SolverOptions.cpp
index 8956945..7561065 100644
--- a/escriptcore/src/SolverOptions.cpp
+++ b/escriptcore/src/SolverOptions.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SolverOptions.h b/escriptcore/src/SolverOptions.h
index e6bf867..c8975c5 100644
--- a/escriptcore/src/SolverOptions.h
+++ b/escriptcore/src/SolverOptions.h
@@ -1,7 +1,7 @@
 
 /******************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -635,7 +635,7 @@ public:
     /**
         Sets the symmetry flag for the coefficient matrix to ``flag``.
 
-        \param flag If true, the symmetry flag is set otherwise reset.
+        \param symmetry If true, the symmetry flag is set otherwise reset.
     */
     void setSymmetry(bool symmetry);
 
@@ -685,7 +685,7 @@ public:
     /**
         Sets the flag to indicate automatic selection of the inner tolerance.
 
-        \param adapt If ``true``, the inner tolerance is selected automatically
+        \param adaption If ``true``, the inner tolerance is selected automatically
     */
     void setInnerToleranceAdaption(bool adaption);
 
@@ -714,7 +714,7 @@ public:
     /**
         Sets the flag to indicate the acceptance of a failure of convergence.
 
-        \param accept If ``true``, any failure to achieve convergence is
+        \param acceptance If ``true``, any failure to achieve convergence is
                accepted.
     */
     void setAcceptanceConvergenceFailure(bool acceptance);
@@ -740,7 +740,7 @@ public:
     /**
         Sets the flag to use local preconditioning
 
-        \param use If ``true``, local proconditioning on each MPI rank is
+        \param local If ``true``, local proconditioning on each MPI rank is
                applied
     */
     void setLocalPreconditioner(bool local);
@@ -818,7 +818,8 @@ public:
     /**
         Sets the interpolation method for the AMG preconditioner.
 
-        \param method key of the interpolation method to be used, should be in
+        \param interpolation key of the interpolation method to be used,
+               should be in
                `SO_INTERPOLATION_CLASSIC_WITH_FF_COUPLING`,
                `SO_INTERPOLATION_CLASSIC`, `SO_INTERPOLATION_DIRECT`
     */
diff --git a/escriptcore/src/SolverOptionsException.cpp b/escriptcore/src/SolverOptionsException.cpp
index 9b7e7e2..9928eb1 100644
--- a/escriptcore/src/SolverOptionsException.cpp
+++ b/escriptcore/src/SolverOptionsException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SolverOptionsException.h b/escriptcore/src/SolverOptionsException.h
index e96fb42..cdb28a5 100644
--- a/escriptcore/src/SolverOptionsException.h
+++ b/escriptcore/src/SolverOptionsException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SplitWorld.cpp b/escriptcore/src/SplitWorld.cpp
index 243a51a..4b292de 100644
--- a/escriptcore/src/SplitWorld.cpp
+++ b/escriptcore/src/SplitWorld.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,11 +13,16 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "esysUtils/Esys_MPI.h"
 #include "SplitWorld.h"
 #include "AbstractDomain.h"
 #include "SplitWorldException.h"
 #include "SplitWorldException.h"
+#include "esysUtils/pyerr.h"
 
 #include <iostream>
 #include <sstream>
@@ -26,6 +31,13 @@ using namespace boost::python;
 using namespace escript;
 namespace rs=escript::reducerstatus;
 
+
+double SplitWorld::getScalarVariable(const std::string& name)
+{
+    // do we have a variable of that name?
+    return localworld->getScalarVariable(name);
+}
+
 SplitWorld::SplitWorld(unsigned int numgroups, MPI_Comm global)
     :localworld((SubWorld*)0), swcount(numgroups>0?numgroups:1), jobcounter(1), manualimport(false)
 {
@@ -64,7 +76,7 @@ SplitWorld::SplitWorld(unsigned int numgroups, MPI_Comm global)
 	subcom=esysUtils::makeInfo(0);
 	corrcom=esysUtils::makeInfo(0);
     #endif
-    localworld=SubWorld_ptr(new SubWorld(globalcom, subcom,corrcom, swcount, grank%wsize));
+    localworld=SubWorld_ptr(new SubWorld(globalcom, subcom,corrcom, swcount, grank%wsize,manualimport));
     localid=grank/wsize;
 }
 
@@ -100,203 +112,68 @@ object SplitWorld::buildDomains(tuple t, dict kwargs)
 }
 
 
-namespace
-{
-
-// Throw all values in and get the maximum
-// This is not an AllReduce because we need to use Tagged Communication so as not to interfere with 
-// other messages / collective ops which the SubWorld's Jobs might be using
-// This is implemented by sending to rank 0
-bool checkResultInt(int res, int& mres, esysUtils::JMPI& info)
-{
-#ifdef ESYS_MPI
-    const int leader=0;
-    const int BIGTAG=esysUtils::getSubWorldTag();
-    if (info->size==1)
-    {
-	mres=res;
-	return true;
-    }
-    else
-    {
-	if (info->rank!=leader)
-	{
-	    if (MPI_Send(&res, 1, MPI_INT, leader, BIGTAG, info->comm)!=MPI_SUCCESS)
-	    {
-		return false;
-	    }
-	    if (MPI_Recv(&mres, 1, MPI_INT, leader, BIGTAG, info->comm,0)!=MPI_SUCCESS)
-	    {
-		return false;
-	    }
-	}
-	else
-	{
-	    MPI_Request* reqs=new MPI_Request[info->size-1];
-	    int* eres=new int[info->size-1];
-	    for (int i=0;i<info->size-1;++i)
-	    {
-		MPI_Irecv(eres+i, 1, MPI_INT, i+1, BIGTAG, info->comm, reqs+i);	  
-	    }
-	    if (MPI_Waitall(info->size-1, reqs, 0)!=MPI_SUCCESS)
-	    {
-		delete[] reqs;
-		return false;
-	    }
-	    // now we have them all, find the max
-	    mres=res;
-	    for (int i=0;i<info->size-1;++i)
-	    {
-		if (mres<eres[i])
-		{
-		    mres=eres[i];
-		}
-	    }
-	    // now we know what the result should be
-	    // send it to the others
-	    for (int i=0;i<info->size-1;++i)
-	    {
-		MPI_Isend(&mres, 1, MPI_INT, i+1, BIGTAG, info->comm, reqs+i);	  
-	    }
-	    if (MPI_Waitall(info->size-1, reqs,0)!=MPI_SUCCESS)
-	    {
-		return false;
-	    }
-	}
-      
-    }
-    return true;
-#else
-    mres=res;
-    return true;
-#endif
-}
-
-
-}
-
-
-// Update the vector to indicate the interest of all subworlds in each variable
-bool SplitWorld::getVariableInterest(std::vector<char>& vb)
-{
-
-	std::vector<char> lvec;
-	localworld->getVariableStatus(lvec);	// this tells us what our local world wants  
-	
-	vb.resize(localworld->getNumVars()*swcount);
-
-      // now we need to ask all the world leaders about their involvement
-#ifdef ESYS_MPI
-    if (localworld->amLeader())
-    {
-	// The leaders of each world, send their variable information to the proc "0" in
-	// the global world (which will be the leader of subworld "0").
-	//    There is an issue here if this operation fails
-	if (MPI_Gather(&lvec[0], localworld->getNumVars(), MPI_CHAR, &vb[0], vb.size(), 
-		   MPI_CHAR, 0, localworld->getCorrMPI()->comm)!=MPI_SUCCESS) 
-	{
-	    for (size_t i=0;i<vb.size();++i)
-	    {
-		vb[i]=rs::ERROR;
-	    }
-	}
-    }
-    // now share the combined info with all processes
-    if ((MPI_Bcast(&vb[0], vb.size(), MPI_CHAR, 0, globalcom->comm)!=MPI_SUCCESS)
-	  || (vb[0]==rs::ERROR))
-    {
-	return false;
-    }
-#else
-      // since there is only one world, we just copy lvec to global
-    vb=lvec;
-#endif  
-    return true;
-}
-
 // Executes all pending jobs on all subworlds
 void SplitWorld::runJobs()
 {
     esysUtils::NoCOMM_WORLD ncw;	// it's destructor will unset the flag
+    localworld->resetInterest();    
     try 
     {
 	distributeJobs();
 	int mres=0;
 	std::string err;
-	std::vector<char> impexpdetail;
-	std::vector<char> variableinterest;
-	do
+	do	// only here so I can "break" to the end
 	{
-	      // make sure that any jobs which register as needing imports get them
-	      // first check local jobs to find out what they need
-	    if (!localworld->findImports(manualimport, err))
+		// find out which variables each world has and wants  (global op)
+	    if (!localworld->synchVariableInfo(err))
 	    {
 		mres=4;
-		err="Error while finding imports.";
 		break;
 	    }
-	      // Now we find out what the other worlds want 
-	    if (!getVariableInterest(variableinterest))
+		// distribute values to worlds as needed  (global op)
+	    if (!localworld->synchVariableValues(err))
 	    {
 		mres=4;
-		err="Error while gathering variable use information.";
 		break;
 	    }
-	      // If there are any variables which are needed but not present on local
-	    if (!localworld->deliverGlobalImports(variableinterest, err))
-	    {
-		mres=4;
-		err="Error delivering global imports.";
-		break;
-	    }
-	      
+		// give values to jobs (local op)	
 	    if (!localworld->deliverImports(err))
 	    {
-		mres=4;
-		err="Error delivering local imports.";
-		break;
-	    }	  
-	    // now we actually need to run the jobs
-	    // everybody will be executing their localworld's jobs
-	    int res=localworld->runJobs(err);	
-
-// 	    // take this opportunity to clean up (the python side)
-// 	    localworld->clearImportExports();
-	    // now we find out about the other worlds
-	    if (!checkResultInt(res, mres, globalcom))
-	    {
-		throw SplitWorldException("MPI appears to have failed.");
-	    }
-	    if (mres>1)	// 1 and 0 are normal returns, >1 is some sort of error
-	    {
-	      break; 
+		mres=4;	// can't jump to the end because this is a local op
 	    }
-	    if (!localworld->localTransport(impexpdetail, err))
+	    else	// import delivery was successful
 	    {
-		mres=4;
-		err="Error in localTransport.";
-		break;
+	        // now we actually need to run the jobs
+	        // everybody will be executing their localworld's jobs
+	        mres=localworld->runJobs(err);	
+
+                if (mres<2)
+	        {
+                    if (!localworld->localTransport(err))
+		    {
+		        mres=4;		// both running jobs and local reduction are local ops
+		    }
+	        }
 	    }
-	    
-	      // at this point, the remote world has all the reductions done
-	      // now we need to do the global merges
-	      
-	    if (!localworld->checkRemoteCompatibility(err))
-	    {
-		mres=4;
-		err="Error in checkRemoteCompatibility.";
-		break;
-	    }
-	    if (!localworld->reduceRemoteValues())
-	    {
-		mres=4;
-		err="Error in reduceRemoteValue.";
-		break;	      
-	    }	    
-	} while (mres==1);
-	if (mres==0)
+
+	} while (false);
+        int res=mres;
+        // now we find out about the other worlds
+        if (!esysUtils::checkResult(res, mres, globalcom))
+        {
+	    throw SplitWorldException("MPI appears to have failed.");
+        }
+
+	localworld->clearJobs();
+	  // at this point, the remote world has all the reductions done
+	  // now we need to do the global merges
+	if (!localworld->checkRemoteCompatibility(err))
 	{
-	    clearAllJobs();
+	    mres=4;
+	    err="Error in checkRemoteCompatibility.";
+	}
+	if (mres==0)	
+	{  	
 	    return;
 	}
 	else if (mres==2)
@@ -320,7 +197,6 @@ void SplitWorld::runJobs()
 	else if (mres==4)
 	{
 	    throw SplitWorldException("While processing exports: "+err);
-	
 	}
 	else
 	{ 
@@ -342,9 +218,63 @@ void SplitWorld::addJob(boost::python::object creator, boost::python::tuple tup,
 {
     create.push_back(creator);
     tupargs.push_back(tup);
-    kwargs.push_back(kw);
+    kwargs.push_back(kw);  
+}
+
+/**
+  creates exactly one instance of the job on each world.
+  This bypasses the normal job allocation method (since that does not guarantee one job per world)
+*/
+void SplitWorld::addJobPerWorld(boost::python::object creator, boost::python::tuple tup, boost::python::dict kw)
+{
+    std::string errmsg;
+    int errstat=0;
+    try
+    {
+	// we need to add some things to the kw map
+	kw["domain"]=localworld->getDomain();
+	kw["jobid"]=object(jobcounter+localid);
+	kw["swcount"]=object(swcount);
+	kw["swid"]=object(localid);
+	object job=creator(*tup, **kw);
+	localworld->addJob(job);
+    }
+    catch (boost::python::error_already_set e)
+    {
+	errstat=1;
+	getStringFromPyException(e, errmsg);
+    }
+    jobcounter+=swcount;
+    clearPendingJobs();
+    
+    // MPI check to ensure that it worked for everybody
+    int mstat=0;
+    if (!esysUtils::checkResult(errstat, mstat, globalcom))
+    {
+	throw SplitWorldException("MPI appears to have failed.");
+    }
+    
+      // Now we need to find out if anyone else had an error      
+    if (!esysUtils::checkResult(errstat, mstat, globalcom))
+    {
+	throw SplitWorldException("MPI appears to have failed.");
+    }
+    errstat=mstat;  
+      
+    if (errstat==1)
+    {
+	char* resultstr=0;
+	// now we ship around the error message - This should be safe since
+	// eveyone must have finished their Jobs to get here
+	if (!esysUtils::shipString(errmsg.c_str(), &resultstr, globalcom->comm))
+	{
+	    throw SplitWorldException("MPI appears to have failed.");
+	}      
+	throw SplitWorldException(std::string("(During Job creation/distribution) ")+resultstr);
+    }  
 }
 
+
 // At some point, we may need there to be more isolation here
 // and trap any python exceptions etc, but for now I'll just call the constructor
 void SplitWorld::addVariable(std::string name, boost::python::object creator, boost::python::tuple ntup, boost::python::dict kwargs)
@@ -356,7 +286,7 @@ void SplitWorld::addVariable(std::string name, boost::python::object creator, bo
 	throw SplitWorldException("Creator function did not produce a reducer.");
     }
     Reducer_ptr rp=ex();
-    localworld->addVariable(name, rp, manualimport);
+    localworld->addVariable(name, rp);
 }
 
 
@@ -365,10 +295,36 @@ void SplitWorld::removeVariable(std::string name)
     localworld->removeVariable(name);
 }
 
+
+void SplitWorld::clearVariable(std::string name)
+{
+    localworld->clearVariable(name);
+}
+
+std::list<std::pair<std::string, bool> > SplitWorld::getVarList()
+{
+    return localworld->getVarList();
+}
+
+
+boost::python::object SplitWorld::getVarPyList()
+{
+    std::list<std::pair<std::string, bool> > r=localworld->getVarList();
+    boost::python::list l;
+    for (std::list<std::pair<std::string, bool> >::iterator it=r.begin();it!=r.end();++it)
+    {
+        boost::python::list t;
+	t.append(it->first);
+	t.append(it->second);
+        l.append(t);
+    }
+    return l;
+}
+
 void SplitWorld::clearAllJobs()
 {
     clearPendingJobs();
-    clearActiveJobs();
+    localworld->clearJobs();
 }
 
 void SplitWorld::clearPendingJobs()
@@ -378,14 +334,11 @@ void SplitWorld::clearPendingJobs()
     kwargs.clear();
 }
 
-void SplitWorld::clearActiveJobs()
-{
-    localworld->clearJobs();
-}
-
 // All the job params are known on all the ranks.
+// note that perWorld jobs will already be loaded directly to the worlds
 void SplitWorld::distributeJobs()
 {
+    std::string errmsg;
     unsigned int numjobs=create.size()/swcount;
     unsigned int start=create.size()/swcount*localid;
     if (localid<create.size()%swcount)
@@ -407,6 +360,8 @@ void SplitWorld::distributeJobs()
 	    // we need to add some things to the kw map
 	    kwargs[i]["domain"]=localworld->getDomain();
 	    kwargs[i]["jobid"]=object(jobcounter+i);
+	    kwargs[i]["swcount"]=object(swcount);
+	    kwargs[i]["swid"]=object(localid);    
 	    object job=create[i](*(tupargs[i]), **(kwargs[i]));
 	    localworld->addJob(job);
 	}
@@ -414,21 +369,35 @@ void SplitWorld::distributeJobs()
     catch (boost::python::error_already_set e)
     {
 	errstat=1;
+	getStringFromPyException(e, errmsg);
     }
     jobcounter+=create.size();
     clearPendingJobs();
     
     // MPI check to ensure that it worked for everybody
     int mstat=0;
-    if (!esysUtils::checkResult(errstat, mstat, globalcom->comm))
+    if (!esysUtils::checkResult(errstat, mstat, globalcom))
     {
 	throw SplitWorldException("MPI appears to have failed.");
     }
     
+      // Now we need to find out if anyone else had an error      
+    if (!esysUtils::checkResult(errstat, mstat, globalcom))
+    {
+	throw SplitWorldException("MPI appears to have failed.");
+    }
+    errstat=mstat;  
+      
     if (errstat==1)
     {
-	throw SplitWorldException("distributeJobs: Job creation failed.");
-	clearActiveJobs();
+	char* resultstr=0;
+	// now we ship around the error message - This should be safe since
+	// eveyone must have finished their Jobs to get here
+	if (!esysUtils::shipString(errmsg.c_str(), &resultstr, globalcom->comm))
+	{
+	    throw SplitWorldException("MPI appears to have failed.");
+	}      
+	throw SplitWorldException(std::string("(During Job creation/distribution) ")+resultstr);
     }
 }
 
@@ -472,6 +441,26 @@ boost::python::object raw_addJob(boost::python::tuple t, boost::python::dict kwa
     return object();
 }
 
+boost::python::object raw_addJobPerWorld(boost::python::tuple t, boost::python::dict kwargs)
+{
+    int l=len(t);
+    if (l<2)
+    {
+	throw SplitWorldException("Insufficient parameters to addJobPerWorld.");
+    }
+    extract<SplitWorld&> exw(t[0]);
+    if (!exw.check())
+    {
+	throw SplitWorldException("First parameter to addJobPerWorld must be a SplitWorld.");
+    }
+    SplitWorld& ws=exw();
+    object creator=t[1]; 
+    tuple ntup=tuple(t.slice(2,l));	// strip off the object param
+    ws.addJobPerWorld(creator, ntup, kwargs);
+    return object();
+}
+
+
 // expects, splitworld, name of var, constructor function for the reducer, any constructor params
 boost::python::object raw_addVariable(boost::python::tuple t, boost::python::dict kwargs)
 {
diff --git a/escriptcore/src/SplitWorld.h b/escriptcore/src/SplitWorld.h
index cff163e..ca595bc 100644
--- a/escriptcore/src/SplitWorld.h
+++ b/escriptcore/src/SplitWorld.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,11 +20,18 @@
 #include <boost/smart_ptr.hpp>
 #include "esysUtils/Esys_MPI.h"
 #include "SubWorld.h"
-#include "Reducer.h"
+#include "AbstractReducer.h"
 namespace escript
 {
 
-/** class to hold a collection of MPI processes and a communicator linking them
+/** 
+ * Provides an interface to a collection of subworlds.
+ * Variables are declared and jobs are submitted using this interface.
+ * Internally, the work is done by a local subworld instance (and associated communicators which 
+ * this process belongs to). The local subworld will communicate with subworlds 
+ * in other processes as needed.
+ * The main reason for this class, is to insulate users from the MPI type thinking needed for
+ * subworlds and instead provide an interface which allows them to think about subworlds as a group.
 */
 class SplitWorld
 {
@@ -36,12 +43,17 @@ public:
     void runJobs();
     
     void addJob(boost::python::object creator, boost::python::tuple tup, boost::python::dict kw);
+    void addJobPerWorld(boost::python::object creator, boost::python::tuple tup, boost::python::dict kw);
     
     void addVariable(std::string name, boost::python::object creator, boost::python::tuple ntup, boost::python::dict kwargs);
-    void removeVariable(std::string name);    
-    void clearActiveJobs();
+    void removeVariable(std::string name); 
+    void clearVariable(std::string name); 
+    std::list<std::pair<std::string, bool> > getVarList();
+    boost::python::object getVarPyList();
+
     void clearAllJobs();
 
+    double getScalarVariable(const std::string& name);
     
     
     
@@ -61,7 +73,7 @@ private:
     bool manualimport;		// if false, all reduced vars will be shipped to all subworlds    
     void clearPendingJobs();
     void distributeJobs();
-    bool getVariableInterest(std::vector<char>& vb);    
+
 };
 
 
@@ -76,6 +88,11 @@ boost::python::object raw_buildDomains(boost::python::tuple t, boost::python::di
 boost::python::object raw_addJob(boost::python::tuple t, boost::python::dict kwargs);
 
 /**
+ used to invoke the SplitWorld version from python (in lieu of a method based equivalent to raw_function)
+*/
+boost::python::object raw_addJobPerWorld(boost::python::tuple t, boost::python::dict kwargs);
+
+/**
  used to add a reducer for shared values.
 */
 boost::python::object raw_addVariable(boost::python::tuple t, boost::python::dict kwargs);
diff --git a/escriptcore/src/SplitWorldException.cpp b/escriptcore/src/SplitWorldException.cpp
index 47bcd19..c38fefc 100644
--- a/escriptcore/src/SplitWorldException.cpp
+++ b/escriptcore/src/SplitWorldException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SplitWorldException.h b/escriptcore/src/SplitWorldException.h
index d08c7ca..17785e5 100644
--- a/escriptcore/src/SplitWorldException.h
+++ b/escriptcore/src/SplitWorldException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SubWorld.cpp b/escriptcore/src/SubWorld.cpp
index 384e7d8..97dd05d 100644
--- a/escriptcore/src/SubWorld.cpp
+++ b/escriptcore/src/SubWorld.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,8 +14,16 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "SubWorld.h"
 #include "SplitWorldException.h"
+#include "esysUtils/pyerr.h"
+
+#include "MPIDataReducer.h"
+#include "MPIScalarReducer.h"
 
 #include <boost/python/import.hpp>
 #include <boost/python/dict.hpp>
@@ -27,11 +35,15 @@ namespace bp=boost::python;
 using namespace esysUtils;
 namespace rs=escript::reducerstatus;
 
-SubWorld::SubWorld(JMPI& global, JMPI& comm, JMPI& corr, unsigned int subworldcount, unsigned int local_id)
-    :everyone(global), swmpi(comm), corrmpi(corr), domain((AbstractDomain*)0), swcount(subworldcount), localid(local_id)
-{
-
+using namespace std;
 
+SubWorld::SubWorld(JMPI& global, JMPI& comm, JMPI& corr, unsigned int subworldcount, unsigned int local_id, bool manualimport)
+    :everyone(global), swmpi(comm), corrmpi(corr), domain((AbstractDomain*)0), 
+    swcount(subworldcount), localid(local_id), manualimports(manualimport)
+#ifdef ESYS_MPI    
+    ,globalinfoinvalid(true)
+#endif    
+{
 }
 
 SubWorld::~SubWorld()
@@ -68,41 +80,97 @@ void SubWorld::clearJobs()
     jobvec.clear();
 }
 
-  // query the jobs to find the names of requested imports
-bool SubWorld::findImports(bool manualimports, std::string& errmsg)
+void SubWorld::setMyVarState(const std::string& vname, char state)
 {
-      // set all imports to false (if manual import is true) else set all to true
-      // query each job:
-      //		1) get its wantedvalues field
-      //		2) check to ensure each value is actually a known variable
-      //		3) set its value in import map to true
-    if (!manualimports)
+    setVarState(vname, state, localid);
+}
+
+void SubWorld::setAllVarsState(std::string& vname, char state)
+{
+#ifdef ESYS_MPI  
+      // we need to know where the variable is in thbe sequence
+    str2char::iterator it=varstate.find(vname);
+    size_t c=0;
+    for (;it!=varstate.end();++it,++c)
     {
-	  // import everything
-	for (str2bool::iterator it=importmap.begin();it!=importmap.end();++it)
+	if (it->first==vname)
 	{
-	    it->second=true;
+	    break;
 	}
     }
-    else		// manual imports
+    if (it==varstate.end())
+    {
+	return;
+    }
+    it->second=state;
+    c--;		// we now have the sequence position of the variable
+    for (char z=rs::NONE; z<=rs::NEW;++z)
+    {
+	globalvarcounts[vname][z]=0;
+    }
+    globalvarcounts[vname][state]=swcount;
+    if (!globalinfoinvalid)	// it will be updated in the next synch
     {
-	  // import nothing
- 	for (str2bool::iterator it=importmap.begin();it!=importmap.end();++it)
+	for (size_t p=c;p<globalvarinfo.size();p+=getNumVars())
 	{
-	    it->second=false;
-	}     
-	
-	for (size_t i=0;i<jobvec.size();++i)
+	    globalvarinfo[p]=state;
+	}
+    }
+#else
+    varstate[vname]=state;
+#endif    
+  
+  
+}
+
+
+void SubWorld::setVarState(const std::string& vname, char state, int rank)
+{
+#ifdef ESYS_MPI  
+      // we need to know where the variable is in thbe sequence
+    str2char::iterator it;
+    size_t c=0;
+    for (it=varstate.begin();it!=varstate.end();++it,++c)
+    {
+	if (it->first==vname)
+	{
+	    break;
+	}
+    }
+    if (it==varstate.end())
+    {
+	return;
+    }
+    
+	// we now have the sequence position of the variable
+    if (!globalinfoinvalid)	// it will be updated in the next synch
+    {
+	unsigned char ostate=globalvarinfo[c+getNumVars()*rank];
+	globalvarinfo[c+getNumVars()*rank]=state;
+	globalvarcounts[vname][ostate]--;
+	globalvarcounts[vname][state]++;
+    }
+    if (rank==localid)	// we are updating our own state so we need to change "varstate"
+    {
+	it->second=state;
+    }
+#else
+    varstate[vname]=state;
+#endif
+}
+
+
+// this will give the imported values to interested jobs
+bool SubWorld::deliverImports(std::string& errmsg)
+{
+    for (size_t i=0;i<jobvec.size();++i)
+    {
+	if (manualimports)
 	{
 	    bp::list wanted=bp::extract<bp::list>(jobvec[i].attr("wantedvalues"))();		  
 	    for (size_t j=0;j<len(wanted);++j)
 	    {
-		bp::extract<std::string> exs(wanted[j]);
-		if (!exs.check()) 
-		{
-		    errmsg="names in wantedvalues must be strings";
-		    return false;
-		}
+		bp::extract<std::string> exs(wanted[j]);	// must have been checked by now
 		std::string n=exs();
 		  // now we need to check to see if this value is known
 		str2reduce::iterator it=reducemap.find(n);
@@ -111,36 +179,43 @@ bool SubWorld::findImports(bool manualimports, std::string& errmsg)
 		    errmsg="Attempt to import variable \""+n+"\". SplitWorld was not told about this variable.";
 		    return false;
 		}
-		importmap[n]=true;
+		try
+		{
+		    jobvec[i].attr("setImportValue")(it->first, reducemap[it->first]->getPyObj());
+		}
+		catch (boost::python::error_already_set e)
+		{
+		    getStringFromPyException(e, errmsg);   	      
+		    return false;
+		} 
+	    }
+	}
+	else
+	{
+	      // For automatic imports, we want to import "Everything" into every job.
+	      // However, we don't want to import things with no value yet
+	    for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it)
+	    {
+		if (it->second->hasValue())
+		{		  
+		    try
+		    {
+			jobvec[i].attr("setImportValue")(it->first, it->second->getPyObj());
+		    }
+		    catch (boost::python::error_already_set e)
+		    {
+			getStringFromPyException(e, errmsg);   	      
+			return false;
+		    }
+		}
 	    }
 	}
     }
     return true;
 }
 
-// this will give the imported values to interested jobs
-bool SubWorld::deliverImports(std::string& errmsg)
-{
-    
-      // set all imports to false (if manual import is true) else set all to true
-      // query each job:
-      //		1) get its wantedvalues field
-      //		2) check to ensure each value is actually a known variable
-      //		3) set its value in import map to true
-    errmsg="Haven't implemented this bit yet.";
-    return false;
-//    return true;
-}
-
-
-// takes a vector of bools of size 2*number of variables
-// Each entry in the first group is true if this subworld has at least one job which exports that variable.
-// Each entry in the second group is true if there is at least one Job in this world which wishes
-// to import that variable.
-// The order of the variables is determined by the order of keys in the reducemap
-// Q: Why does it take chars then?
-// A: Because I want raw storage that I can pass via MPI and vector<bool> is special cased.
-bool SubWorld::localTransport(std::vector<char>& vb, std::string& errmsg)
+// Gather exported values from jobs and merge them in the reducer
+bool SubWorld::localTransport(std::string& errmsg)
 {
     for (size_t i=0;i<jobvec.size();++i)
     {  
@@ -172,120 +247,130 @@ bool SubWorld::localTransport(std::vector<char>& vb, std::string& errmsg)
 	    }
 	    if (!(it->second)->valueCompatible(o2))
 	    {
-		errmsg="Attempt to export variable \""+name+"\" with an incompatible value.";
+		errmsg="Attempt to export variable \""+name+"\" with an incompatible value. Using ";
+		errmsg+=(it->second)->description();
 		return false;
 	    }
 	    if (!(it->second)->reduceLocalValue(o2, errmsg))
 	    {
 		return false;	// the error string will be set by the reduceLocalValue
 	    }
+	    setMyVarState(name, rs::NEW);
 	}
-    }
-
-	// If we get here, all of the (local) exports worked
-	// Now, lets make a record for distrubtion    
-    size_t l=reducemap.size();
-    vb.resize(l*2);
-    size_t i=0;
-    for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it, ++i)
-    {
-	if (it->second->hasValue())
-	{
-	    vb[i]=1;
-	}
-	else
-	{
-	    vb[i]=0;
-	}
-	if (importmap[it->first])
-	{
-	    vb[i+l]=1;
-	}
-	else
-	{
-	    vb[i+l]=0;	  
-	}
-    }     
+    } 
     return true;      
 }
-/*
-// Deal with the i-th job's exports
-bool SubWorld::processExportsLocal(size_t i, std::string& errmsg)
+
+void SubWorld::debug()
 {
-    bp::dict expmap=bp::extract<bp::dict>(jobvec[i].attr("exportedvalues"))();	
-    bp::list items=expmap.items();
-    size_t l=bp::len(items);
-    for (int j=0;j<l;++j)
-    {
-	bp::object o1=items[j][0];
-	bp::object o2=items[j][1];
-	bp::extract<std::string> ex1(o1);
-	if (!ex1.check())
+    using namespace std;
+    using namespace escript::reducerstatus;
+    std::cout << "Variables:";
+#ifdef ESYS_MPI
+	if (!globalinfoinvalid)
 	{
-	    errmsg="Job attempted export using a name which was not a string.";
-	    return false;
+	    cout << "{ NONE INTR OLD OINT NEW }";
 	}
-	std::string name=ex1();
-	std::map<std::string, Reducer_ptr>::iterator it=reducemap.find(name);
-	if (it==reducemap.end())
+	else
 	{
-	    errmsg="Attempt to export variable \""+name+"\". SplitWorld was not told about this variable.";
-	    return false;
+	    cout << "(no valid global info)";
 	}
-	// so now we know it is a known name, we check that it is not None and that it is compatible
-	if (o2.is_none())
+#endif	    
+    std::cout << std::endl;
+    int i=0;
+    for (str2char::iterator it=varstate.begin();it!=varstate.end();++it,++i)
+    {
+	std::cout << it->first << ": ";
+	std::cout << reducemap[it->first]->description() << " ";
+	switch (it->second)
 	{
-	    errmsg="Attempt to export variable \""+name+"\" with value of None, this is not permitted.";
-	    return false;
+	  case NONE: cout << "NONE "; break;
+	  case INTERESTED: cout << "INTR "; break;
+	  case OLDINTERESTED: cout << "OINT "; break;
+	  case OLD: cout << "OLD  "; break;
+	  case NEW: cout << "NEW  "; break;
 	}
-	if (!(it->second)->valueCompatible(o2))
+#ifdef ESYS_MPI
+	if (!globalinfoinvalid)
 	{
-	    errmsg="Attempt to export variable \""+name+"\" with an incompatible value.";
-	    return false;
+	    cout << "{ ";
+	    for (unsigned char z=rs::NONE;z<=rs::NEW;++z)
+	    {
+		cout << globalvarcounts[it->first][z] << ' ';
+	    }
+	    cout << " } ";
+	    
 	}
-	if (!(it->second)->reduceLocalValue(o2, errmsg))
+	else
 	{
-	    return false;	// the error string will be set by the reduceLocalValue
+	    cout << "(no valid global info)";
 	}
+#endif	
+	cout << endl;
     }
-    return true;
-}*/
-/*
+    
+#ifdef ESYS_MPI
 
-void SubWorld::populateVarMoveInfo(vector<char>& vb)
-{
-    size_t l=reducemap.size();
-    vb.resize(l*2);
-    for (str2reduce::iterator it=reducemap.begin(), int i=0;it!=reducemap.end();++it, ++i)
+    if (!globalinfoinvalid)
     {
-	if (it->second->hasValue())
+	cout << "[";
+	for (size_t i=0;i<globalvarinfo.size();++i)
 	{
-	    vb[i]=1;
-	}
-	else
-	{
-	    vb[i]=0;
-	}
-	if (importmap[it->first])
-	{
-	    vb[i+l]=1;
-	}
-	else
-	{
-	    vb[i+l]=0;	  
+	    if (i%getNumVars()==0)
+	    {
+		cout << " ";
+	    }
+	    cout << (short)globalvarinfo[i];
 	}
+	cout << " ] ";
+	
     }
-}*/
 
-// clears out all the old import and export values from _Jobs_
-// does not clear values out of reducers
-void SubWorld::clearImportExports()
+
+#endif
+    std::cout << "Debug end\n";
+    std::cout.flush();
+  
+}
+
+
+// not to be called while running jobs
+// The tricky bit, is that this could be be called between job runs
+// this means that the values of variables may not have been synched yet
+double SubWorld::getScalarVariable(const std::string& name)
 {
-    for (size_t i=0;i<jobvec.size();++i)
+    str2reduce::iterator it=reducemap.find(name);
+    if (it==reducemap.end())
     {
-	jobvec[i].attr("clearImports")();
-	jobvec[i].attr("clearExports")();
+	throw SplitWorldException("No variable of that name.");
     }
+	// need to indicate we are interested in the variable
+    if (varstate[name]==rs::NONE)
+    {
+	setMyVarState(name, rs::INTERESTED);
+    }
+    else if (varstate[name]==rs::OLD)
+    {
+      	setMyVarState(name, rs::OLDINTERESTED);
+    }
+	// anything else, indicates interest anyway
+#ifdef ESYS_MPI
+    std::string errmsg;
+    if (!synchVariableInfo(errmsg))
+    {
+	throw SplitWorldException(std::string("(Getting scalar --- Variable information) ")+errmsg);
+    }
+    if (!synchVariableValues(errmsg))
+    {
+	throw SplitWorldException(std::string("(Getting scalar --- Variable value) ")+errmsg);
+    }
+#endif
+	
+    if (dynamic_cast<MPIScalarReducer*>(it->second.get())==0)
+    {
+	throw SplitWorldException("Variable is not scalar.");
+    }
+    return dynamic_cast<MPIScalarReducer*>(it->second.get())->getDouble();
 }
 
 bool SubWorld::checkRemoteCompatibility(std::string& errmsg)
@@ -300,131 +385,368 @@ bool SubWorld::checkRemoteCompatibility(std::string& errmsg)
     return true;
 }
 
-
-bool SubWorld::reduceRemoteValues()
+#ifdef ESYS_MPI  
+  
+bool SubWorld::makeComm(MPI_Comm& sourcecom, MPI_Comm& subcom,std::vector<int>& members)
 {
-    for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it)
-    {
-	if (! it->second->reduceRemoteValues(corrmpi))
-	{
-	    return false;
-	}
-    }
-    return true;    
+      MPI_Group sourceg, g;
+      if (MPI_Comm_group(sourcecom, &sourceg)!=MPI_SUCCESS) {return false;}
+      if (MPI_Group_incl(sourceg, members.size(), &members[0], &g)!=MPI_SUCCESS) {return false;}      
+      // then create a communicator with that group
+      if (MPI_Comm_create(sourcecom, g, &subcom)!=MPI_SUCCESS) 
+      {
+	return false;
+	
+      }
+      return true;
 }
 
-
-  // Work out which variables we need to make available to python
-bool SubWorld::deliverImports(std::vector<char>& vb, std::string& errmsg)
+// a group with NEW nodes at the front and INT and OLDINT at the back
+// NONE worlds get an empty communicator
+bool SubWorld::makeGroupComm1(MPI_Comm& srccom, int vnum, char mystate, MPI_Comm& com)
 {
-    errmsg="Haven't implemented this yet";
-    return false;
+      if ((mystate==rs::NEW)
+	    || (mystate==rs::INTERESTED)
+	    || (mystate==rs::OLDINTERESTED))
+      {
+      // first create a group with [updates, interested and oldinterested in it]
+	  std::vector<int> members;
+	  for (int i=0+vnum;i<globalvarinfo.size();i+=getNumVars())
+	  {
+	      // make a vector of the involved procs with New at the front
+	      switch (globalvarinfo[i])
+	      {
+		case rs::NEW:   members.insert(members.begin(), i/getNumVars()); break;
+		case rs::INTERESTED:     
+		case rs::OLDINTERESTED:
+			  members.push_back(i/getNumVars());
+			  break;
+	      }
+	  }
+	  return makeComm(srccom, com, members);
+      }
+      else	// for people not in involved in the value shipping
+      {		// This would be a nice time to use MPI_Comm_create_group
+		// but it does not exist in MPI2.1
+	  return MPI_Comm_create(srccom, MPI_GROUP_EMPTY, &com);
+      }
 }
 
-bool SubWorld::amLeader()
+// A group with a single OLD or OLDINT at the front and all the INT worlds 
+// following it
+bool SubWorld::makeGroupComm2(MPI_Comm& srccom, int vnum, char mystate, MPI_Comm& com)
 {
-    return swmpi->rank==0;
+      if ((mystate==rs::OLD)
+	    || (mystate==rs::INTERESTED)
+	    || (mystate==rs::OLDINTERESTED))
+      {
+	  // first create a group with [old, interested and oldinterested in it]
+	  std::vector<int> members;
+	  bool havesrc=false;
+	  for (int i=0+vnum;i<globalvarinfo.size();i+=getNumVars())
+	  {
+	      // make a vector of the involved procs with New at the front
+	      switch (globalvarinfo[i])
+	      {
+		case rs::NEW:   return false;  break;
+		case rs::INTERESTED: members.push_back(i/getNumVars());  break;     
+		case rs::OLD: 
+		case rs::OLDINTERESTED:
+			  if (!havesrc)
+			  {
+			      members.insert(members.begin(), i/getNumVars());
+			      havesrc=true;
+			  }
+			  break;
+	      }
+	  }		
+	  return makeComm(srccom, com, members);
+      }
+      else	// for people not in involved in the value shipping
+      {		// This would be a nice time to use MPI_Comm_create_group
+		// but it does not exist in MPI2.1	
+	  return MPI_Comm_create(srccom, MPI_GROUP_EMPTY, &com);
+      }
 }
 
+#endif  
 
-// Look at the vector of interest and send around variables to where they need to be
-// To try to make error reporting consistant, every variable transfer will be attempted,
-// even if an early one fails.
-bool SubWorld::deliverGlobalImports(std::vector<char>& vb, std::string& errmsg)
+
+bool SubWorld::synchVariableValues(std::string& err)
 {
-#ifdef ESYS_MPI  
-    size_t maxv=std::numeric_limits<size_t>::max();   // largest possible value in size_t
-    size_t nv=getNumVars();
-    str2reduce::iterator rmi=reducemap.begin();
-    char error=0;
-    for (size_t i=0;i<nv;++i, ++rmi)
-    {
-	size_t earliest=maxv;	
-	for (int s=0;s<swcount;++s)
+#ifdef ESYS_MPI    
+    // There are three possibilities here but since all worlds have the same knowledge
+    // we can be sure that they will all make the same choice
+    // 1) No updates are required
+    // 2) There is a single world with a new value so it can broadcast it
+    // 3) There are multiple worlds with updates
+    
+    // need to keep track of which vars have updates
+    std::vector<std::string> varswithupdates;
+    
+    int vnum=0;    
+    for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it, ++vnum)
+    {
+         // check to see if anyone needs it
+	int needcount=0; // who wants a new value
+	int newcount=0;	// who has a new version
+	int oldcount=0;	// who has an old version
+	int oldintcount=0;
+	newcount=globalvarcounts[it->first][rs::NEW];
+	oldcount=globalvarcounts[it->first][rs::OLD];
+	oldintcount=globalvarcounts[it->first][rs::OLDINTERESTED];
+	needcount=globalvarcounts[it->first][rs::INTERESTED]+oldintcount;
+	if (newcount>0)
 	{
-	    if (vb[s*nv+i]==rs::HAVE)	// This world has a copy of the value
-	    {
-		earliest=s;	      
-	    }
+	    varswithupdates.push_back(it->first);
+	}
+	if (needcount+newcount+oldcount==0)
+	{
+	    continue;		// noone cares about this variable
 	}
-	if (earliest==maxv)
+	if (needcount>0 && (oldcount+oldintcount+newcount)==0)
 	{
-	      // noone has a value for the requested variable
-	      // We could make that an error condition but for now, I'll let
-	      // any job scripts deal with that
+	    err="Import attempted for a variable \""+(it->first)+"\" with no value.";
+	    return false;
+	}
+	    // worlds have the variable but noone is interested in it
+	    // note that if there are multiple new values, we still want to merge them
+	if ((needcount==0) && (newcount<=1))
+	{
+	    continue;	
+	}
+	if (swcount==1)
+	{		// nobody else to communicate with
 	    continue;
 	}
-	  // do I need that variable (but don't have a value)?
-	if (vb[localid*nv+i]==rs::INTERESTED)
+	    // to reach this point, there must be >=1 source and >=1 sink and multiple worlds
+	    // first deal updates as source(s)
+	if (newcount==1)	// only one update so send from that
 	{
-	    if (!rmi->second->recvFrom(localid, earliest, corrmpi)) 
+	    MPI_Comm com;
+	    if (!makeGroupComm1(corrmpi->comm, vnum, varstate[it->first],com))
 	    {
-		error=1;
-		errmsg="Error receving value for variable.";
+		err="Error creating group for sharing values,";
+		return false;
 	    }
-	} 
-	else if (localid==earliest)	// we will be the one to ship the value to others
-	{
-	    for (unsigned int target=0;target<swcount;++target)	// look through all worlds and see who we need to send to
+	    if (varstate[it->first]!=rs::NONE && varstate[it->first]!=rs::OLD)
 	    {
-		if (vb[target*nv+i]==rs::INTERESTED)	// nobody who has the value will be marked as INTERESTED
+		it->second->groupSend(com);
+		  // Now record the fact that we have the variable now
+		if (varstate[it->first]==rs::INTERESTED)
 		{
-		    if (!rmi->second->sendTo(localid, target, corrmpi))
-		    {
-			error=1;
-			errmsg="Error sending value for variable.";
-		    }
+		    setMyVarState(it->first, rs::OLDINTERESTED); 
 		}
 	    }
+	    // disolve the group
+	    MPI_Comm_free(&com);
+	    continue;
 	}
-    }
-      // It is possible that one or more subworlds were not participating in a failed transfer so we need to check
-    char nerr;  
-    if (MPI_Allreduce(&error, &nerr, 1, MPI_CHAR, MPI_MAX, everyone->comm)!=MPI_SUCCESS)
-    {
-	if (errmsg.empty())
+	if (newcount>1)
 	{
-	    errmsg="Error checking for other errors.";
+	    // form a group to send to [updates and interested and oldinterested]
+	    MPI_Comm com;
+	    if (!makeGroupComm1(corrmpi->comm, vnum, varstate[it->first],com))
+	    {
+		err="Error creating group for sharing values,";
+		return false;
+	    }
+	    it->second->groupReduce(com,varstate[it->first]);
+	    MPI_Comm_free(&com);	    
+	    continue;
 	}
-	return false;
+	    // at this point, we need to ship info around but there are no updates
+	    // that is, we are shipping an old copy
+	    // picking a source arbitarily (the first one in the array)
+	    
+	    // but first, eliminate the special case where the only interested ones
+	    // already have a copy
+	if (oldintcount==needcount)
+	{
+	    continue;
+	}
+	MPI_Comm com;
+	if (!makeGroupComm2(corrmpi->comm, vnum, varstate[it->first],com))
+	{
+	    err="Error creating group for sharing values";
+	    return false;
+	}
+	// form group to send to [latestsource and interested]
+	it->second->groupSend(com);
+	// dissolve the group	
+	MPI_Comm_free(&com);
     }
-    if (nerr)
-    {
-	errmsg="Another process experienced an error delivering variables.";
-	return false;
+	// now we need to age any out of date copies of vars
+    for (size_t i=0;i<varswithupdates.size();++i)
+    {      
+        std::string vname=varswithupdates[i];
+        	if (varstate[vname]==rs::NEW)
+	{
+	    setMyVarState(vname, rs::OLD);
+	}
+	else if (varstate[vname]==rs::OLD)
+	{
+	    setMyVarState(vname, rs::NONE);
+	    reducemap[vname]->clear();
+	}
     }
-    return !error;
-#else
-    return true;
-#endif    
+#endif
+    return true;    
 }
 
+bool SubWorld::amLeader()
+{
+    return swmpi->rank==0;
+}
 
-
-// Resize the vector so it holds the current number of variables
-// walk along all variables in the maps and determine, what our interest is in each one
-void SubWorld::getVariableStatus(std::vector<char>& vb)
+// Find out which variables the local queued jobs are interested in
+// share that info around
+bool SubWorld::synchVariableInfo(std::string& err)
 {
-    vb.resize(reducemap.size());
-    str2reduce::const_iterator rm=reducemap.begin();
-    str2bool::const_iterator im=importmap.begin();
-    for (unsigned int i=0;rm!=reducemap.end();++rm,++im,++i)
+    if (manualimports)		// manual control over imports
     {
-	if (rm->second->hasValue())
+	for (size_t i=0;i<jobvec.size();++i)
 	{
-	    vb[i]=rs::HAVE;	// we have a value to contribute
+	    bp::list wanted=bp::extract<bp::list>(jobvec[i].attr("wantedvalues"))();		  
+	    for (size_t j=0;j<len(wanted);++j)
+	    {
+		bp::extract<std::string> exs(wanted[j]);
+		if (!exs.check()) 
+		{
+		    err="names in wantedvalues must be strings";
+		    return false;
+		}
+		std::string n=exs();
+		  // now we need to check to see if this value is known
+		str2char::iterator it=varstate.find(n);
+		if (it==varstate.end())
+		{
+		    err="Attempt to import variable \""+n+"\". SplitWorld was not told about this variable.";
+		    return false;
+		}
+		// So at least one job wants this variable
+		switch (it->second)
+		{
+		  case rs::NONE: it->second=rs::INTERESTED; break;
+		  case rs::INTERESTED: break;
+		  case rs::OLD: it->second=rs::OLDINTERESTED; break;
+		  case rs::NEW: break;
+		  default:
+		    err="Unknown variable state";
+		    return false;
+		}
+	    }
 	}
-	else if (im->second)
+    }
+        // Make a vector to hold the info from the map (so we can send it around)
+    std::vector<char> lb(getNumVars(), rs::NONE);
+    size_t i=0;
+    for (str2char::iterator it=varstate.begin();it!=varstate.end();++it,++i)
+    {
+        lb[i]=it->second;
+    }
+
+
+#ifdef ESYS_MPI
+        // Vector to hold the result
+    globalvarinfo.resize(getNumVars()*swcount, rs::NONE);
+    if (amLeader())	// we only need on representative from each world to send
+    {
+	// The leaders of each world, send their variable information to the proc "0" in
+	// the global world (which will be the leader of subworld "0").
+	//    There is an issue here if this operation fails
+	if (MPI_Gather(&lb[0], getNumVars(), MPI_CHAR, &globalvarinfo[0], getNumVars(), 
+		   MPI_CHAR, 0, getCorrMPI()->comm)!=MPI_SUCCESS) 
+	{
+	    for (size_t i=0;i<globalvarinfo.size();++i)
+	    {
+		globalvarinfo[i]=rs::ERROR;
+	    }
+	}      
+    }
+    // now share the combined info with all processes
+    if ((MPI_Bcast(&globalvarinfo[0], globalvarinfo.size(), MPI_CHAR, 0, everyone->comm)!=MPI_SUCCESS)
+	  || (globalvarinfo[0]==rs::ERROR))
+    {
+	err="Error while gathering variable use information.";
+	return false;	
+    }
+      // now we convert that info into a form which is easier to read
+    int p=0;  
+    for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it,++p)
+    {
+	globalvarcounts[it->first][rs::NONE]=0;
+	globalvarcounts[it->first][rs::INTERESTED]=0;
+	globalvarcounts[it->first][rs::OLD]=0;
+	globalvarcounts[it->first][rs::OLDINTERESTED]=0;
+	globalvarcounts[it->first][rs::NEW]=0;
+	for (int j=p;j<globalvarinfo.size();j+=getNumVars())
 	{
-	    vb[i]=rs::INTERESTED;	// we are interested in this variable
+	    if (globalvarinfo[j]<=rs::NEW)
+	    {
+		globalvarcounts[it->first][globalvarinfo[j]]++;
+	    }
 	}
-	else
+    }
+    
+#endif    
+    if (!manualimports)	
+    {
+	    // import all known variables _BUT_ don't import something if noone has a value
+	    // for it  
+	int vnum=0;
+	for (str2char::iterator it=varstate.begin();it!=varstate.end();++it, ++vnum)
 	{
-	    vb[i]=rs::NONE;	// we have no interest in this variable
+#ifdef ESYS_MPI
+	      // if at least one world has a value for a variable
+	    if (globalvarcounts[it->first][rs::OLDINTERESTED] 
+	         + globalvarcounts[it->first][rs::OLD] 
+	         + globalvarcounts[it->first][rs::NEW] > 0 )
+	    {
+#endif
+	      
+		if (it->second==rs::NONE)
+		{
+		    it->second=rs::INTERESTED;
+		}
+		else if (it->second==rs::OLD)
+		{
+		    it->second=rs::OLDINTERESTED;
+		}
+#ifdef ESYS_MPI
+		  // now we need to update the globalvarinfo to record all the extra interest
+		for (int j=vnum;j<globalvarinfo.size();j+=getNumVars())
+		{
+		    if (globalvarinfo[j]==rs::NONE)
+		    {
+			globalvarinfo[j]=rs::INTERESTED;
+			globalvarcounts[it->first][rs::NONE]--;
+			globalvarcounts[it->first][rs::INTERESTED]++;			
+		    }
+		    else if (globalvarinfo[j]==rs::OLD)
+		    {
+			globalvarinfo[j]=rs::OLDINTERESTED;
+			globalvarcounts[it->first][rs::OLD]--;
+			globalvarcounts[it->first][rs::OLDINTERESTED]++;			
+		    }
+		  
+		}
+	    }
+#endif	
 	}
     }
+#ifdef ESYS_MPI    
+    globalinfoinvalid=false;
+#endif
+
+    return true;
 }
 
+// // merge / ship values as required
+// bool SubWorld::synchVariableValues(std::string& err)
+// {
+//     return reduceRemoteValues(err);
+// }
 
 // if 4, a Job performed an invalid export
 // if 3, a Job threw an exception 
@@ -434,7 +756,6 @@ void SubWorld::getVariableStatus(std::vector<char>& vb)
 char SubWorld::runJobs(std::string& errormsg)
 {
     errormsg.clear();
-    bp::object gettrace=bp::import("traceback").attr("format_exc");
     int ret=0;
     try
     {
@@ -456,28 +777,7 @@ char SubWorld::runJobs(std::string& errormsg)
     } 
     catch (boost::python::error_already_set e)
     {
-	using namespace boost::python;
-  	PyObject* ptype=0;
- 	PyObject* pvalue=0;
- 	PyObject* ptraceback=0;
- 	PyErr_Fetch(&ptype, &pvalue, &ptraceback);
-	PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
- 
-	PyObject* errobj=PyObject_Str(pvalue);
-
-#ifdef ESPYTHON3	
-	PyObject* rr=PyUnicode_AsASCIIString(errobj);
-	errormsg=PyBytes_AsString(rr);
-	Py_XDECREF(rr);
-#else
-	errormsg=PyString_AsString(errobj);
-#endif
-	Py_XDECREF(errobj);
-
-	Py_XDECREF(ptype);
-	Py_XDECREF(pvalue);
-	Py_XDECREF(ptraceback);
- 	
+	getStringFromPyException(e, errormsg);      
 	return 3;
     }  
     return ret;
@@ -489,26 +789,71 @@ size_t SubWorld::getNumVars()
 }
 
 // if manual import is false, add this new variable to all the Jobs in this world
-void SubWorld::addVariable(std::string& name, Reducer_ptr& rp, bool manualimport)
+void SubWorld::addVariable(std::string& name, Reducer_ptr& rp)
 {
     if (reducemap.find(name)!=reducemap.end())
     {
 	std::ostringstream oss;
-	oss << "There is already a variable called " << name;
 	throw SplitWorldException(oss.str());    
     }
     reducemap[name]=rp;
-    if (!manualimport)
+    varstate[name]=reducerstatus::NONE;
+    if (!manualimports)
     {
 	for (size_t i=0;i<jobvec.size();++i)
 	{
 	    jobvec[i].attr("requestImport")(name);
 	}
     }
+#ifdef ESYS_MPI
+    globalinfoinvalid=true;	// since we need to regenerate globalvarinfo
+#endif
 }
 
 void SubWorld::removeVariable(std::string& s)
 {
     reducemap.erase(s);
+    varstate.erase(s);
+#ifdef ESYS_MPI    
+    globalinfoinvalid=true;
+    globalvarinfo.resize(0);
+    globalvarcounts.erase(s);
+#endif    
 }
 
+void SubWorld::clearVariable(std::string& name)
+{
+    str2reduce::iterator it=reducemap.find(name);
+    if (it==reducemap.end())
+    {
+	return;
+    }
+    it->second->reset();
+      // if we got here, we must have a valid name so we can change state directly
+    setAllVarsState(name, rs::NONE);
+}
+
+void SubWorld::resetInterest()
+{
+    for (str2char::iterator it=varstate.begin();it!=varstate.end();++it)
+    {
+	if (it->second==rs::INTERESTED)
+	{
+	    it->second=rs::NONE;
+	}
+	else if (it->second==rs::OLDINTERESTED)
+	{
+	    it->second=rs::OLD;
+	}
+    }
+}
+
+std::list<std::pair<std::string, bool> > SubWorld::getVarList()
+{
+    std::list<std::pair<std::string,bool> > res;
+    for (std::map<std::string, Reducer_ptr>::iterator it=reducemap.begin();it!=reducemap.end();++it)
+    {
+        res.push_back(std::pair<std::string, bool>(it->first, it->second->hasValue()));
+    }
+    return res;
+}
diff --git a/escriptcore/src/SubWorld.h b/escriptcore/src/SubWorld.h
index 3bb9fbe..8ce5df5 100644
--- a/escriptcore/src/SubWorld.h
+++ b/escriptcore/src/SubWorld.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -19,60 +19,113 @@
 
 #include "esysUtils/Esys_MPI.h"
 #include "AbstractDomain.h"
-#include "Reducer.h"
+#include "AbstractReducer.h"
 
 namespace escript
 {
   
-/** class to hold a collection of MPI processes and a communicator linking them
+/** This class represents a collection of MPI processes which will execute a number of Jobs (in series).
+ * There could be a number of SubWorlds (executing jobs in parallel) in the overall system.
+ * All jobs running in a SubWorld will use a common domain object.
+ * After each job runs, any values it exports will be merged into local reducer objects.
+ * Global (ie with the participation of other SubWorlds) reductions and interworld transfers
+ * are handled after the current batch of jobs have completed.
+ * That is, variable values should not be considered up to date until the whole batch is complete.
+ * Further, after a batch has completed, multiple subworlds may have copies of the variable,
+ * if the variable is modified in a later batch, this may result in unwanted double counting.
+ * eg: v (reduce:+)
+ * Batch 1:
+ *   world 1:   v+=1,2,3  --- local v=6
+ *   world 2:   v+=1,2    --- local v=3
+ * What is the value of v in this split world?   v=9
+ * 
+ * Batch 2:
+ *   world 1:  v+=1   --- local v=1+9
+ *   world 2:  v+=1   --- local v=1+9
+ * What is the value of v? 20, not 11
 */
 class SubWorld : public boost::enable_shared_from_this<SubWorld>
 {
 public:
-    SubWorld(esysUtils::JMPI& globalcom, esysUtils::JMPI& comm, esysUtils::JMPI& corr, unsigned int subworldcount, unsigned int local_id);
+    SubWorld(esysUtils::JMPI& globalcom, esysUtils::JMPI& comm, esysUtils::JMPI& corr, unsigned int subworldcount, unsigned int local_id, bool manualimport);
     ~SubWorld();
     void setDomain(Domain_ptr d);
     Domain_ptr getDomain();
     esysUtils::JMPI& getMPI();
     esysUtils::JMPI& getCorrMPI();
-    void addJob(boost::python::object j);
-    char runJobs(std::string& errmsg);
-    void clearJobs();
-    void clearImportExports();
-    void addVariable(std::string&, Reducer_ptr& red, bool manualimport);
+    void addJob(boost::python::object j);		// add a Job to the current batch
+    char runJobs(std::string& errmsg);		// run all jobs in the current batch
+    void clearJobs();				// remove all jobs in the current batch
+
+    void addVariable(std::string&, Reducer_ptr& red);
     void removeVariable(std::string& name);  
+    void clearVariable(std::string& name);
+    std::list<std::pair<std::string, bool> > getVarList();
     size_t getNumVars();
     
-    bool localTransport(std::vector<char>& vb, std::string& errmsg);
-    bool checkRemoteCompatibility(std::string& errmsg);
-    bool reduceRemoteValues(std::string& errmsg);
-    bool deliverImports(std::vector<char>& vb, std::string& errmsg);
-    
+    bool localTransport(std::string& errmsg);	// gather exported values from jobs
+    bool checkRemoteCompatibility(std::string& errmsg);	// check to ensure values
+						// in all worlds are compatible
     
-    bool findImports(bool manualimports, std::string& errmsg);
-    bool deliverImports(std::string& errmsg);
-    bool deliverGlobalImports(std::vector<char>& vb, std::string& errmsg);
-    void getVariableStatus(std::vector<char>& vb);
-    bool reduceRemoteValues();    
+    bool deliverImports(std::string& errmsg);	// load imports into Job objects
     bool amLeader();	// true if this proc is the leader for its world
     
+    double getScalarVariable(const std::string& name);
+    
+    void debug();	// print out current state information
+    
+    
+    
+    bool synchVariableInfo(std::string& err);
+    bool synchVariableValues(std::string& err);    
+    void resetInterest();    
     
 private:
     esysUtils::JMPI everyone;	// communicator linking all procs in all subworlds
     esysUtils::JMPI swmpi;	// communicator linking all procs in this subworld
     esysUtils::JMPI corrmpi;	// communicator linking corresponding procs in all subworlds
+				// eg: If this proc is the first in its domain, then corrmpi
+				//     links to the other "first in its domain" processes.
+				//      (So one in each SubWorld).
     escript::Domain_ptr domain;
-    std::vector<boost::python::object> jobvec;
+    std::vector<boost::python::object> jobvec;	// jobs in the current batch
     
     
     unsigned int swcount;		// number of subwords
     unsigned int localid;    	// my position within the sequence
     
 typedef std::map<std::string, Reducer_ptr> str2reduce;  
-typedef std::map<std::string, bool> str2bool;
+typedef std::map<std::string, unsigned char> str2char;
     str2reduce reducemap;		// map: name ->reducer for that variable
-    str2bool importmap;
+    str2char varstate;		// using the state values from Reducer.h
 
+    bool manualimports;
+    
+#ifdef ESYS_MPI    
+    std::vector<unsigned char> globalvarinfo;	// info about which worlds want which vars
+typedef std::map<unsigned char, int> countmap;
+typedef std::map<std::string, countmap> str2countmap;
+    str2countmap globalvarcounts;
+    bool globalinfoinvalid;
+    
+    
+    bool makeComm(MPI_Comm& sourcecom, MPI_Comm& subcom,std::vector<int>& members);
+
+
+    // a group with NEW nodes at the front and INT and OLDINT at the back
+    // NONE worlds get an empty communicator
+    bool makeGroupComm1(MPI_Comm& srccom, int vnum, char mystate, MPI_Comm& com);
+
+    // A group with a single OLD or OLDINT at the front and all the INT worlds 
+    // following it
+    bool makeGroupComm2(MPI_Comm& srccom, int vnum, char mystate, MPI_Comm& com);    
+    
+#endif
+    
+      // change the various views of a variable's state
+    void setMyVarState(const std::string& vname, char state);
+    void setVarState(const std::string& vname, char state, int rank);
+    void setAllVarsState(std::string& name, char state);
 };
 
 typedef boost::shared_ptr<SubWorld> SubWorld_ptr;
diff --git a/escriptcore/src/SystemMatrixException.cpp b/escriptcore/src/SystemMatrixException.cpp
index 85cd109..dfd3d06 100644
--- a/escriptcore/src/SystemMatrixException.cpp
+++ b/escriptcore/src/SystemMatrixException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/SystemMatrixException.h b/escriptcore/src/SystemMatrixException.h
index e60b622..ae1339c 100644
--- a/escriptcore/src/SystemMatrixException.h
+++ b/escriptcore/src/SystemMatrixException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Taipan.cpp b/escriptcore/src/Taipan.cpp
index 5c7c056..4b43dce 100644
--- a/escriptcore/src/Taipan.cpp
+++ b/escriptcore/src/Taipan.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Taipan.h b/escriptcore/src/Taipan.h
index e415b57..55f38e5 100644
--- a/escriptcore/src/Taipan.h
+++ b/escriptcore/src/Taipan.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/TestDomain.cpp b/escriptcore/src/TestDomain.cpp
index 4240a22..1f43a57 100644
--- a/escriptcore/src/TestDomain.cpp
+++ b/escriptcore/src/TestDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DomainException.h"
 #include "TestDomain.h"
diff --git a/escriptcore/src/TestDomain.h b/escriptcore/src/TestDomain.h
index 98b4366..8f3472b 100644
--- a/escriptcore/src/TestDomain.h
+++ b/escriptcore/src/TestDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/TransportProblemException.cpp b/escriptcore/src/TransportProblemException.cpp
index d8b7a70..60b5b58 100644
--- a/escriptcore/src/TransportProblemException.cpp
+++ b/escriptcore/src/TransportProblemException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/TransportProblemException.h b/escriptcore/src/TransportProblemException.h
index f0cbcdb..1cdd077 100644
--- a/escriptcore/src/TransportProblemException.h
+++ b/escriptcore/src/TransportProblemException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/UnaryFuncs.h b/escriptcore/src/UnaryFuncs.h
index 6051127..1e2505f 100644
--- a/escriptcore/src/UnaryFuncs.h
+++ b/escriptcore/src/UnaryFuncs.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/UnaryOp.h b/escriptcore/src/UnaryOp.h
index f847234..78de32b 100644
--- a/escriptcore/src/UnaryOp.h
+++ b/escriptcore/src/UnaryOp.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/UtilC.h b/escriptcore/src/UtilC.h
index 367ed03..c19d388 100644
--- a/escriptcore/src/UtilC.h
+++ b/escriptcore/src/UtilC.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/Utils.cpp b/escriptcore/src/Utils.cpp
index 0b9cc0e..0f59cc9 100644
--- a/escriptcore/src/Utils.cpp
+++ b/escriptcore/src/Utils.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,12 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+#ifndef OVERLORDPATH
+  #define OVERLORDPATH ""
+#endif
 
 #include <fstream>
 #include <string.h>
@@ -163,6 +169,147 @@ ESCRIPT_DLL_API int getMPIWorldSum(const int val) {
   return out;
 }
 
+#define CHILD_FAIL 2
+#define CHILD_COMPLETE 4
+
+#ifndef _WIN32
+#ifdef ESYS_MPI
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <arpa/inet.h>
+int prepareSocket(unsigned short *port, int *key) {
+    if (getMPIRankWorld() != 0)
+        return 0;
+    int sfd = socket(AF_INET, SOCK_STREAM, 0);
+    if (sfd < 0) {
+        perror("socket creation failure");
+        return -1;
+    }
+    int opt = 1;
+    if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) < 0) {
+        perror("socket option setting failure");
+        close(sfd);
+        return -1;
+    }
+
+    struct sockaddr_in addr;
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(0);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+        perror("bind failure");
+        close(sfd);
+        return -1;
+    }
+
+    if (listen(sfd, SOMAXCONN) < 0) {
+        perror("listen failure");
+        close(sfd);
+        return -1;
+    }
+    
+    struct sockaddr actual;
+    unsigned int size = sizeof(actual);
+    if (getsockname(sfd, &actual, &size) < 0) {
+        perror("failed when determining bound port number");
+        close(sfd);
+        return -1;
+    }
+    
+    //if size > sizeof(actual), some info was truncated, but certainly not port
+    
+    *port = ntohs(((struct sockaddr_in *) &actual)->sin_port);
+
+    unsigned int seed = time(NULL) % UINT_MAX;
+    *key = rand_r(&seed);
+    return sfd;
+}
+
+int check_data(unsigned int max, fd_set *all, fd_set *valid, int key, int sfd) {
+    int ret = 0;
+    for (int i = 0; i <= max; i++) {
+        if (i == sfd)
+            continue;
+        if (FD_ISSET(i, all)) {
+            int provided = 0;
+            if (recv(i, &provided, sizeof(int), MSG_WAITALL) == sizeof(int)
+                    && provided == key) {
+                char deadspace[1024];
+                while ((provided = recv(i, deadspace, 1024, 0))) {
+                    if (provided == -1) {
+                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                            continue;
+                        } else {
+                            perror("connection failure");
+                            return CHILD_FAIL;
+                        }
+                    }
+                }
+                return CHILD_COMPLETE;
+            } else {
+                FD_CLR(i, all);
+                close(i);
+            }
+        }
+    }
+    return ret;
+}
+
+void close_all(unsigned int maxfd, fd_set *all) {
+    for (int i = 0; i <= maxfd; i++) {
+        if (FD_ISSET(i, all))
+            close(i);
+    }
+}
+int waitForCompletion(int sfd, int key) {
+    if (getMPIRankWorld() != 0)
+        return 0;
+    int timeout = 10; //max of 10 seconds with no communication
+    
+    fd_set all, valid; 
+    FD_ZERO(&all);
+    FD_SET(sfd, &all);
+    time_t last_good_time = time(NULL);
+    unsigned int maxfd = sfd;
+    while (time(NULL) - last_good_time < timeout) {
+        struct timeval timer = {1,0}; //1 sec, 0 usec
+        int count = select(maxfd + 1, &all, NULL, NULL, &timer);
+        if (count == -1) { //error
+            if (errno == EINTR) {
+                continue; //just a signal, continue as we were
+            } else {
+                perror("socket operation error");
+                close(sfd);
+                return -1;
+            }
+        } else if (FD_ISSET(sfd, &all)) { //new connection
+            int connection = accept(sfd, NULL, NULL);
+            if (connection > maxfd)
+                maxfd = connection;
+            FD_SET(connection, &all);
+            FD_CLR(connection, &valid);
+            time(&last_good_time);
+            count--;
+        }
+        if (count > 0) { //something to read, either connection key or state
+            int res = check_data(maxfd, &all, &valid, key, sfd);
+            if (res == CHILD_FAIL) {
+                return -1;
+            } else if (res == CHILD_COMPLETE) {
+                close_all(maxfd, &all);
+                return 0;
+            }
+        }
+    }
+    close_all(maxfd, &all);
+    fprintf(stderr, "Connection to child process timed out\n");
+    return -1;
+}
+#endif //ESYS_MPI
+#endif //not _WIN32
+
 ESCRIPT_DLL_API int runMPIProgram(boost::python::list args) {
 #ifdef ESYS_MPI
     MPI_Comm intercomm;
@@ -170,21 +317,57 @@ ESCRIPT_DLL_API int runMPIProgram(boost::python::list args) {
     int errors;
     int nargs = boost::python::extract<int>(args.attr("__len__")());
     std::string cmd = boost::python::extract<std::string>(args[0]);
-    std::vector<std::string> cpp_args(nargs);
+#ifdef _WIN32
     char** c_args = new char*[nargs];
-    char* c_cmd = const_cast<char*>(cmd.c_str());
+    char* c_cmd = const_cast<char*>(cmd.c_str());;
     // skip command name in argument list
     for (int i=1; i<nargs; i++) {
 	    cpp_args[i-1]=boost::python::extract<std::string>(args[i]);
         c_args[i-1]=const_cast<char*>(cpp_args[i-1].c_str());
     }
-    c_args[nargs-1]=NULL;
     MPI_Info_create(&info);
     MPI_Comm_spawn(c_cmd, c_args, 1, info, 0, MPI_COMM_WORLD, &intercomm, &errors);
     MPI_Info_free(&info);
     delete[] c_args;
+
     return errors;
-#else
+#else //#ifdef _WIN32
+    char** c_args = new char*[2+nargs];
+    std::vector<std::string> cpp_args(2+nargs);//allow for wrapper, port, and key
+    char c_cmd[] = OVERLORDPATH"escript-overlord";
+    // skip command name in argument list
+    for (int i=1; i<nargs; i++) {
+	    cpp_args[i+1]=boost::python::extract<std::string>(args[i]);
+        c_args[i+1]=const_cast<char*>(cpp_args[i+1].c_str());
+    }
+    unsigned short port = 0;
+    int key = 0;
+    int sock = prepareSocket(&port, &key);
+    if (getMPIWorldSum(sock) < 0)
+        return -1;
+    c_args[nargs+1]=NULL;
+    char portstr[20] = {'\0'}, keystr[20] = {'\0'};
+    sprintf(portstr, "%d", port);
+    sprintf(keystr, "%d", key);
+    c_args[0] = portstr;
+    c_args[1] = keystr;
+    c_args[2] = const_cast<char*>(cmd.c_str());
+    
+    MPI_Info_create(&info);
+    //force the gmsh process to run on this host as well for network comm
+    char hostname[MPI_MAX_PROCESSOR_NAME];
+    int temp = MPI_MAX_PROCESSOR_NAME;
+    MPI_Get_processor_name(hostname, &temp);
+    char hoststr[] = "host"; //for warnings
+    MPI_Info_set(info, hoststr, hostname);
+    MPI_Comm_spawn(c_cmd, c_args, 1, info, 0, MPI_COMM_WORLD, &intercomm, &errors);
+    MPI_Info_free(&info);
+    delete[] c_args;
+    if (errors != MPI_SUCCESS)
+        return errors;
+    return getMPIWorldMax(waitForCompletion(sock, key));
+#endif //#ifdef _WIN32/else
+#else //#ifdef ESYS_MPI
     std::string cmd;
     int nargs = boost::python::extract<int>(args.attr("__len__")());
     for (int i=0; i<nargs; i++) {
@@ -192,8 +375,10 @@ ESCRIPT_DLL_API int runMPIProgram(boost::python::list args) {
         cmd+=" ";
     }
     return system(cmd.c_str());
-#endif
+#endif //#ifdef ESYS_MPI/else
 }
+#undef CHILD_COMPLETE
+#undef CHILD_FAIL
 
 ESCRIPT_DLL_API double getMachinePrecision() {
    return DBL_EPSILON;
diff --git a/escriptcore/src/Utils.h b/escriptcore/src/Utils.h
index 529fbf6..c525fdb 100644
--- a/escriptcore/src/Utils.h
+++ b/escriptcore/src/Utils.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/WrappedArray.cpp b/escriptcore/src/WrappedArray.cpp
index 3801f56..38f939d 100644
--- a/escriptcore/src/WrappedArray.cpp
+++ b/escriptcore/src/WrappedArray.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/WrappedArray.h b/escriptcore/src/WrappedArray.h
index ed5e722..baafa90 100644
--- a/escriptcore/src/WrappedArray.h
+++ b/escriptcore/src/WrappedArray.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/escriptcpp.cpp b/escriptcore/src/escriptcpp.cpp
index a4c6016..f0a1ad2 100644
--- a/escriptcore/src/escriptcpp.cpp
+++ b/escriptcore/src/escriptcpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Data.h"
 #include "FunctionSpace.h"
 #include "FunctionSpaceFactory.h"
@@ -29,7 +33,10 @@
 #include "TestDomain.h"
 #include "SubWorld.h"
 #include "SplitWorld.h"
-#include "Reducer.h"
+#include "AbstractReducer.h"
+#include "MPIDataReducer.h"
+#include "MPIScalarReducer.h"
+#include "NonReducedVariable.h"
 #include "SolverOptions.h"
 #include "SolverOptionsException.h"
 
@@ -128,22 +135,25 @@ BOOST_PYTHON_MODULE(escriptcpp)
   
 
   class_<escript::AbstractReducer, escript::Reducer_ptr, boost::noncopyable>("Reducer", "", no_init);
-  def("makeDataReducer", escript::makeDataReducer, (arg("op")), "Creates an object to combine values.\n\n"
-  ":param op: name of the operation to use.\n:type op: `str`");
-
+  
   // Why doesn't this have a doc-string?   Because it doesn't compile if you try to add one
   // These functions take a SplitWorld instance as their first parameter
   def("buildDomains", raw_function(escript::raw_buildDomains,2));
   def("addJob", raw_function(escript::raw_addJob,2));
+  def("addJobPerWorld", raw_function(escript::raw_addJobPerWorld,2));
   def("addVariable", raw_function(escript::raw_addVariable,3));
   
   
   def("makeDataReducer", escript::makeDataReducer, arg("op"), "Create a reducer to work with Data and the specified operation.");
-
+  def("makeScalarReducer", escript::makeScalarReducer, arg("op"), "Create a reducer to work with doubles and the specified operation.");
+  def("makeLocalOnly", escript::makeNonReducedVariable, "Create a variable which is not connected to copies in other worlds.");
       
   class_<escript::SplitWorld, boost::noncopyable>("SplitWorld", "Manages a group of sub worlds", init<unsigned int>(args("num_worlds")))
     .def("runJobs", &escript::SplitWorld::runJobs, "Execute pending jobs.")
-    .def("removeVariable", &escript::SplitWorld::removeVariable, arg("name"), "Remove the named variable from the SplitWorld");
+    .def("removeVariable", &escript::SplitWorld::removeVariable, arg("name"), "Remove the named variable from the SplitWorld")
+    .def("clearVariable", &escript::SplitWorld::clearVariable, arg("name"), "Remove the value from the named variable")
+    .def("getVarList", &escript::SplitWorld::getVarPyList, "Lists variables known to the system")
+    .def("getDoubleVariable", &escript::SplitWorld::getScalarVariable);
     
   // This class has no methods. This is deliberate - at this stage, I would like this to be an opaque type  
   class_ <escript::SubWorld, escript::SubWorld_ptr, boost::noncopyable>("SubWorld", "Information about a group of workers.", no_init);
@@ -1029,8 +1039,8 @@ args("source", "q", "r","factor"),
         ":return: requested value. 0 is returned if the value is yet to be defined.\n"
         ":note: If the solver has thrown an exception diagnostic values have an undefined status.")
     .def("hasConverged", &escript::SolverBuddy::hasConverged,"Returns ``True`` if the last solver call has been finalized successfully.\n\n"
-        ":note: if an exception has been thrown by the solver the status of this\n"
-        "flag is undefined.")
+        ":note: if an exception has been thrown by the solver the status of this"
+        "flag is undefined.\n")
     .def("setCoarsening", &escript::SolverBuddy::setCoarsening, args("coarsening"),"Sets the key of the coarsening method to be applied in AMG or AMLI or BoomerAMG\n\n"
         ":param method: selects the coarsening method .\n"
         ":type method: in `DEFAULT`, `YAIR_SHAPIRA_COARSENING`, `RUGE_STUEBEN_COARSENING`, `AGGREGATION_COARSENING`, `CIJP_FIXED_RANDOM_COARSENING`, `CIJP_COARSENING`, `FALGOUT_COARSENING`, `PMIS_COARSENING`, `HMIS_COARSENING`")
@@ -1043,8 +1053,8 @@ args("source", "q", "r","factor"),
     .def("setPreconditioner", &escript::SolverBuddy::setPreconditioner, args("preconditioner"),"Sets the preconditioner to be used.\n\n"
         ":param preconditioner: key of the preconditioner to be used.\n"
         ":type preconditioner: in `ILU0`, `ILUT`, `JACOBI`, `AMG`, `AMLI`, `REC_ILU`, `GAUSS_SEIDEL`, `RILU`, `BOOMERAMG`, `NO_PRECONDITIONER`\n"
-        ":note: Not all packages support all preconditioner. It can be assumed that a package makes a reasonable choice if it encounters an unknown\n"
-        "preconditioner.")
+        ":note: Not all packages support all preconditioner. It can be assumed that a package makes a reasonable choice if it encounters an unknown"
+        "preconditioner.\n")
     .def("getPreconditioner", &escript::SolverBuddy::getPreconditioner,"Returns the key of the preconditioner to be used.\n\n"
         ":rtype: in the list `ILU0`, `ILUT`, `JACOBI`, `AMLI`, `AMG`, `REC_ILU`, `GAUSS_SEIDEL`, `RILU`, `BOOMERAMG`, `NO_PRECONDITIONER`")
     .def("setSmoother", &escript::SolverBuddy::setSmoother, args("smoother"),"Sets the smoother to be used.\n\n"
diff --git a/escriptcore/src/system_dep.h b/escriptcore/src/system_dep.h
index d75248a..f2d0f86 100644
--- a/escriptcore/src/system_dep.h
+++ b/escriptcore/src/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -37,17 +37,7 @@
 #endif
 #include <limits.h>
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/*
- The Intel compiler on windows has an "improved" math library compared to the usual Visual C++ one
- In particular it has a acosh and other similar functions which aren't implemented in Visual C++ math.h
- Note you will get a compile time error if any other header (including system ones) includes math.h whilst mathimf.h
- has been included. As a result system_dep.h must be included FIRST at all times (this prevents math.h from being included).
-*/
-#  include <mathimf.h>
-# else
 #  include <cmath>
-# endif
 
 #ifndef M_PI
 #   define M_PI 3.14159265358979323846
@@ -78,15 +68,6 @@
 #define ESCRIPT_MAX_DATA_RANK 4
 #endif
 
-/* you'll need this one day. */
-#ifndef __const
-# if (defined __STDC__ && __STDC__) || defined __cplusplus
-#  define __const	const
-# else
-#  define __const
-# endif
-#endif
-
 #include <esysUtils/types.h>
 
 #endif
diff --git a/escriptcore/test/DataAlgorithmAdapterTestCase.cpp b/escriptcore/test/DataAlgorithmAdapterTestCase.cpp
index 1e4f6b7..be6f23a 100644
--- a/escriptcore/test/DataAlgorithmAdapterTestCase.cpp
+++ b/escriptcore/test/DataAlgorithmAdapterTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,16 +14,14 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
-#if (defined _WIN32) && (defined __INTEL_COMPILER)
-#include <mathimf.h>
-#else
 #include <cmath>
-#endif
 
 #include "DataAlgorithmAdapterTestCase.h"
 #include "escript/DataExpanded.h"
-// #include "escript/DataArrayView.h"
 #include "escript/DataAlgorithm.h"
 #include "escript/DataTypes.h"
 
diff --git a/escriptcore/test/DataAlgorithmAdapterTestCase.h b/escriptcore/test/DataAlgorithmAdapterTestCase.h
index b0fd2db..013209b 100644
--- a/escriptcore/test/DataAlgorithmAdapterTestCase.h
+++ b/escriptcore/test/DataAlgorithmAdapterTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataBlocks2DTestCase.cpp b/escriptcore/test/DataBlocks2DTestCase.cpp
index ac34d47..6e78149 100644
--- a/escriptcore/test/DataBlocks2DTestCase.cpp
+++ b/escriptcore/test/DataBlocks2DTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataBlocks2DTestCase.h"
 #include "escript/DataBlocks2D.h"
diff --git a/escriptcore/test/DataBlocks2DTestCase.h b/escriptcore/test/DataBlocks2DTestCase.h
index c0b3d49..3d859a9 100644
--- a/escriptcore/test/DataBlocks2DTestCase.h
+++ b/escriptcore/test/DataBlocks2DTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataConstantTestCase.cpp b/escriptcore/test/DataConstantTestCase.cpp
index 4f087b9..9af5e66 100644
--- a/escriptcore/test/DataConstantTestCase.cpp
+++ b/escriptcore/test/DataConstantTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataConstantTestCase.h"
 
diff --git a/escriptcore/test/DataConstantTestCase.h b/escriptcore/test/DataConstantTestCase.h
index 71032dd..e67730c 100644
--- a/escriptcore/test/DataConstantTestCase.h
+++ b/escriptcore/test/DataConstantTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataEmptyTestCase.cpp b/escriptcore/test/DataEmptyTestCase.cpp
index 05963e3..fd83748 100644
--- a/escriptcore/test/DataEmptyTestCase.cpp
+++ b/escriptcore/test/DataEmptyTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "DataEmptyTestCase.h"
 
 #include "escript/DataEmpty.h"
diff --git a/escriptcore/test/DataEmptyTestCase.h b/escriptcore/test/DataEmptyTestCase.h
index 9d86f35..1bfedfb 100644
--- a/escriptcore/test/DataEmptyTestCase.h
+++ b/escriptcore/test/DataEmptyTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataExpandedTestCase.cpp b/escriptcore/test/DataExpandedTestCase.cpp
index a8361bb..d20a075 100644
--- a/escriptcore/test/DataExpandedTestCase.cpp
+++ b/escriptcore/test/DataExpandedTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,16 +14,8 @@
 *
 *****************************************************************************/
 
-#ifdef BADPYTHONMACROS
-// This hack is required for BSD/OSX builds with python 2.7
-// (and possibly others).  It must be the first include.
-// From bug reports online it seems that python redefines
-// some c macros that are functions in c++.
-// c++ doesn't like that!
-#include <Python.h>
-#undef BADPYTHONMACROS
-#endif
-
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "DataExpandedTestCase.h"
 #include "escript/FunctionSpace.h"
diff --git a/escriptcore/test/DataExpandedTestCase.h b/escriptcore/test/DataExpandedTestCase.h
index 7d43e7a..4a7827a 100644
--- a/escriptcore/test/DataExpandedTestCase.h
+++ b/escriptcore/test/DataExpandedTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataFactoryTestCase.cpp b/escriptcore/test/DataFactoryTestCase.cpp
index 962214f..62b0e47 100644
--- a/escriptcore/test/DataFactoryTestCase.cpp
+++ b/escriptcore/test/DataFactoryTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,17 +14,8 @@
 *
 *****************************************************************************/
 
-#ifdef BADPYTHONMACROS
-// This hack is required for BSD/OSX builds with python 2.7
-// (and possibly others).  It must be the first include.
-// From bug reports online it seems that python redefines
-// some c macros that are functions in c++.
-// c++ doesn't like that!
-#include <Python.h>
-#undef BADPYTHONMACROS
-#endif
-
-
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "DataFactoryTestCase.h"
 
diff --git a/escriptcore/test/DataFactoryTestCase.h b/escriptcore/test/DataFactoryTestCase.h
index 1f8811c..3a00d09 100644
--- a/escriptcore/test/DataFactoryTestCase.h
+++ b/escriptcore/test/DataFactoryTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataLazyTestCase.cpp b/escriptcore/test/DataLazyTestCase.cpp
index f8b774c..65792ac 100644
--- a/escriptcore/test/DataLazyTestCase.cpp
+++ b/escriptcore/test/DataLazyTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataLazyTestCase.h"
 
diff --git a/escriptcore/test/DataLazyTestCase.h b/escriptcore/test/DataLazyTestCase.h
index f707e56..a072473 100644
--- a/escriptcore/test/DataLazyTestCase.h
+++ b/escriptcore/test/DataLazyTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataMathsTestCase.cpp b/escriptcore/test/DataMathsTestCase.cpp
index 46fa77e..0ac42e9 100644
--- a/escriptcore/test/DataMathsTestCase.cpp
+++ b/escriptcore/test/DataMathsTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataMathsTestCase.h"
 #include "escript/DataAlgorithm.h"
diff --git a/escriptcore/test/DataMathsTestCase.h b/escriptcore/test/DataMathsTestCase.h
index f2fa14a..1b48f65 100644
--- a/escriptcore/test/DataMathsTestCase.h
+++ b/escriptcore/test/DataMathsTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataTaggedTestCase.cpp b/escriptcore/test/DataTaggedTestCase.cpp
index 816ec02..2e2be5c 100644
--- a/escriptcore/test/DataTaggedTestCase.cpp
+++ b/escriptcore/test/DataTaggedTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataTaggedTestCase.h"
 
diff --git a/escriptcore/test/DataTaggedTestCase.h b/escriptcore/test/DataTaggedTestCase.h
index 12cb527..662e073 100644
--- a/escriptcore/test/DataTaggedTestCase.h
+++ b/escriptcore/test/DataTaggedTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataTestCase.cpp b/escriptcore/test/DataTestCase.cpp
index 60d4a09..08ce98b 100644
--- a/escriptcore/test/DataTestCase.cpp
+++ b/escriptcore/test/DataTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,15 +14,13 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataTestCase.h"
 
-#include <iostream>
-#if defined (_WIN32) && defined (__INTEL_COMPILER)
-#include <mathimf.h>
-#else
 #include <cmath>
-#endif
 
 #include "esysUtils/EsysException.h"
 #include "escript/Data.h"
diff --git a/escriptcore/test/DataTestCase.h b/escriptcore/test/DataTestCase.h
index 86593ca..7ab697e 100644
--- a/escriptcore/test/DataTestCase.h
+++ b/escriptcore/test/DataTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataTypesTestCase.cpp b/escriptcore/test/DataTypesTestCase.cpp
index ef7794b..e49eebe 100644
--- a/escriptcore/test/DataTypesTestCase.cpp
+++ b/escriptcore/test/DataTypesTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataTypesTestCase.h"
 #include "escript/DataAlgorithm.h"
diff --git a/escriptcore/test/DataTypesTestCase.h b/escriptcore/test/DataTypesTestCase.h
index 9295d85..415362c 100644
--- a/escriptcore/test/DataTypesTestCase.h
+++ b/escriptcore/test/DataTypesTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/DataVectorTestCase.cpp b/escriptcore/test/DataVectorTestCase.cpp
index 92e75bd..45ecf47 100644
--- a/escriptcore/test/DataVectorTestCase.cpp
+++ b/escriptcore/test/DataVectorTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "DataVectorTestCase.h"
 
diff --git a/escriptcore/test/DataVectorTestCase.h b/escriptcore/test/DataVectorTestCase.h
index bd55106..60fb823 100644
--- a/escriptcore/test/DataVectorTestCase.h
+++ b/escriptcore/test/DataVectorTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/FunctionSpaceTestCase.cpp b/escriptcore/test/FunctionSpaceTestCase.cpp
index c41e97d..c33860a 100644
--- a/escriptcore/test/FunctionSpaceTestCase.cpp
+++ b/escriptcore/test/FunctionSpaceTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #ifdef BADPYTHONMACROS
 // This hack is required for BSD/OSX builds with python 2.7
 // (and possibly others).  It must be the first include.
diff --git a/escriptcore/test/FunctionSpaceTestCase.h b/escriptcore/test/FunctionSpaceTestCase.h
index 330c971..6dd1a14 100644
--- a/escriptcore/test/FunctionSpaceTestCase.h
+++ b/escriptcore/test/FunctionSpaceTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/SConscript b/escriptcore/test/SConscript
index 8345541..6ec1c39 100644
--- a/escriptcore/test/SConscript
+++ b/escriptcore/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/escriptcore/test/SharedDataTestCase.cpp b/escriptcore/test/SharedDataTestCase.cpp
index 06c0fde..0f9af92 100644
--- a/escriptcore/test/SharedDataTestCase.cpp
+++ b/escriptcore/test/SharedDataTestCase.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -15,6 +15,10 @@
 
 // The purpose of these tests is to check for unwanted sharing of between Data objects
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "SharedDataTestCase.h"
 #include "escript/Data.h"
 #include "escript/EscriptParams.h"
diff --git a/escriptcore/test/SharedDataTestCase.h b/escriptcore/test/SharedDataTestCase.h
index 5b30696..2eb6cf5 100644
--- a/escriptcore/test/SharedDataTestCase.h
+++ b/escriptcore/test/SharedDataTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/TaipanTestCase.cpp b/escriptcore/test/TaipanTestCase.cpp
index a7acc7a..4d94a32 100644
--- a/escriptcore/test/TaipanTestCase.cpp
+++ b/escriptcore/test/TaipanTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "TaipanTestCase.h"
 
diff --git a/escriptcore/test/TaipanTestCase.h b/escriptcore/test/TaipanTestCase.h
index b63eb15..42abe5b 100644
--- a/escriptcore/test/TaipanTestCase.h
+++ b/escriptcore/test/TaipanTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/escript_UnitTest.cpp b/escriptcore/test/escript_UnitTest.cpp
index d85984f..af5e774 100644
--- a/escriptcore/test/escript_UnitTest.cpp
+++ b/escriptcore/test/escript_UnitTest.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/multi_arrayTestCase.cpp b/escriptcore/test/multi_arrayTestCase.cpp
index 59bd6f7..45c9b80 100644
--- a/escriptcore/test/multi_arrayTestCase.cpp
+++ b/escriptcore/test/multi_arrayTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "multi_arrayTestCase.h"
 
diff --git a/escriptcore/test/multi_arrayTestCase.h b/escriptcore/test/multi_arrayTestCase.h
index d9df601..7b7635a 100644
--- a/escriptcore/test/multi_arrayTestCase.h
+++ b/escriptcore/test/multi_arrayTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/test/python/SConscript b/escriptcore/test/python/SConscript
index f48037a..ccea1f9 100644
--- a/escriptcore/test/python/SConscript
+++ b/escriptcore/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -51,9 +51,11 @@ env.Alias('py_tests', [splitext(x)[0]+'.passed' for x in testruns])
 # run all tests
 program = local_env.RunPyUnitTest(alltestruns)
 Depends(program, [py_wrapper_lib, 'install_escript_py', 'build_py_tests'])
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # add a group of tests
 from grouptest import *
-tgroup=GroupTest("$PYTHONRUNNER ",(("ESCRIPT_TEST_DATA_ROOT","$BATCH_ROOT/escriptcore/test/python"),('ESCRIPT_WORKDIR','$BUILD_DIR/escriptcore/test/python')),"$BATCH_ROOT/escriptcore/test/python","$BATCH_ROOT/escriptcore/test/python",testruns)
+tgroup=GroupTest("$PYTHONRUNNER ",(("ESCRIPT_TEST_DATA_ROOT","$BATCH_ROOT/escriptcore/test/python"),('ESCRIPT_WORKDIR','$BUILD_DIR/escriptcore/test/python')),"$BATCH_ROOT/escriptcore/test/python","$BUILD_DIR/escriptcore/test/python",testruns)
 TestGroups.append(tgroup)
 
diff --git a/escriptcore/test/python/TimingTests.py.old b/escriptcore/test/python/TimingTests.py.old
index a39578b..6285eab 100644
--- a/escriptcore/test/python/TimingTests.py.old
+++ b/escriptcore/test/python/TimingTests.py.old
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2010 by University of Queensland
+# Copyright (c) 2003-2010 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au/esscc
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2010 by University of Queensland
+__copyright__="""Copyright (c) 2003-2010 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au/esscc
 Primary Business: Queensland, Australia"""
diff --git a/escriptcore/test/python/run_data_access.py b/escriptcore/test/python/run_data_access.py
index 4fd254b..b4f7730 100644
--- a/escriptcore/test/python/run_data_access.py
+++ b/escriptcore/test/python/run_data_access.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/run_symbolic.py b/escriptcore/test/python/run_symbolic.py
index 699a5ba..9df0686 100644
--- a/escriptcore/test/python/run_symbolic.py
+++ b/escriptcore/test/python/run_symbolic.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/run_testdomain.py b/escriptcore/test/python/run_testdomain.py
index f625275..899229c 100644
--- a/escriptcore/test/python/run_testdomain.py
+++ b/escriptcore/test/python/run_testdomain.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2012-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2012-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/run_units.py b/escriptcore/test/python/run_units.py
index 2a2df3e..ca3b95b 100644
--- a/escriptcore/test/python/run_units.py
+++ b/escriptcore/test/python/run_units.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/run_xml.py b/escriptcore/test/python/run_xml.py
index 395cc97..98f6487 100644
--- a/escriptcore/test/python/run_xml.py
+++ b/escriptcore/test/python/run_xml.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_assemblage.py b/escriptcore/test/python/test_assemblage.py
index 4b28a38..ff792a8 100644
--- a/escriptcore/test/python/test_assemblage.py
+++ b/escriptcore/test/python/test_assemblage.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_assemblage_2Do1.py b/escriptcore/test/python/test_assemblage_2Do1.py
index b1c4fc0..8556c12 100644
--- a/escriptcore/test/python/test_assemblage_2Do1.py
+++ b/escriptcore/test/python/test_assemblage_2Do1.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_assemblage_2Do2.py b/escriptcore/test/python/test_assemblage_2Do2.py
index 11ebc1e..7f11091 100644
--- a/escriptcore/test/python/test_assemblage_2Do2.py
+++ b/escriptcore/test/python/test_assemblage_2Do2.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_assemblage_3Do1.py b/escriptcore/test/python/test_assemblage_3Do1.py
index 7827395..055119b 100644
--- a/escriptcore/test/python/test_assemblage_3Do1.py
+++ b/escriptcore/test/python/test_assemblage_3Do1.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_assemblage_3Do2.py b/escriptcore/test/python/test_assemblage_3Do2.py
index 6dec10d..ab38a81 100644
--- a/escriptcore/test/python/test_assemblage_3Do2.py
+++ b/escriptcore/test/python/test_assemblage_3Do2.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_condEval.py b/escriptcore/test/python/test_condEval.py
index 765aa5c..5146b5b 100644
--- a/escriptcore/test/python/test_condEval.py
+++ b/escriptcore/test/python/test_condEval.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2010-2014 by University of Queensland
+# Copyright (c) 2010-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2010-2014 by University of Queensland
+__copyright__="""Copyright (c) 2010-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_linearPDEs.py b/escriptcore/test/python/test_linearPDEs.py
index d1dd226..190b359 100644
--- a/escriptcore/test/python/test_linearPDEs.py
+++ b/escriptcore/test/python/test_linearPDEs.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_modulefns.py b/escriptcore/test/python/test_modulefns.py
index 51c3b56..606ab9e 100644
--- a/escriptcore/test/python/test_modulefns.py
+++ b/escriptcore/test/python/test_modulefns.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2009-2014 by University of Queensland
+# Copyright (c) 2009-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2009-2014 by University of Queensland
+__copyright__="""Copyright (c) 2009-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_nonLinearPDE.py b/escriptcore/test/python/test_nonLinearPDE.py
index de545fa..f514cb0 100644
--- a/escriptcore/test/python/test_nonLinearPDE.py
+++ b/escriptcore/test/python/test_nonLinearPDE.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_objects.py b/escriptcore/test/python/test_objects.py
index be526b6..4ed5c59 100644
--- a/escriptcore/test/python/test_objects.py
+++ b/escriptcore/test/python/test_objects.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -194,11 +194,13 @@ zwidth/3), 900, True)
                    self.assertTrue(Lsup(res-ref)/Lsup(ref)<self.RES_TOL,"Failed for %s under unified call (no tuple)."%str(fs))
 
 class Test_saveCSV(unittest.TestCase):
+   def setUp(self):
+        self.workdir=ESCRIPT_WORKDIR
 
    def test_csv_header_separator_and_append(self):
         X=self.domain.getX()
         X0=X[0]
-        fname=os.path.join(ESCRIPT_WORKDIR, "test_save1.csv")
+        fname=os.path.join(self.workdir, "test_save1.csv")
         saveDataCSV(fname, C=X, D=X0)
         self.assertTrue(os.path.exists(fname), "test file not created")
         saveDataCSV(fname,append=True, J=X0, H=X)
@@ -227,7 +229,7 @@ class Test_saveCSV(unittest.TestCase):
             FS=self.functionspaces[i]
             X=FS(self.domain).getX()
             X0=X[0]
-            fname=os.path.join(ESCRIPT_WORKDIR, "test_save2.csv")
+            fname=os.path.join(self.workdir, "test_save2.csv")
             saveDataCSV(fname,C=X, D=X0)
             f=open(fname,'r')
             # test number of rows written
diff --git a/escriptcore/test/python/test_pdetools.py b/escriptcore/test/python/test_pdetools.py
index a3bb93b..b865e26 100644
--- a/escriptcore/test/python/test_pdetools.py
+++ b/escriptcore/test/python/test_pdetools.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_shared.py b/escriptcore/test/python/test_shared.py
index 786f73c..c2cbe01 100644
--- a/escriptcore/test/python/test_shared.py
+++ b/escriptcore/test/python/test_shared.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_splitworld.py b/escriptcore/test/python/test_splitworld.py
new file mode 100644
index 0000000..fb6d86e
--- /dev/null
+++ b/escriptcore/test/python/test_splitworld.py
@@ -0,0 +1,478 @@
+
+##############################################################################
+#
+# Copyright (c) 2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+__copyright__="""Copyright (c) 2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+"""
+Tests to ensure that splitworld features operate correctly
+"""
+
+import esys.escriptcore.utestselect as unittest
+from esys.escript import *
+
+from esys.escriptcore.splitworld import *
+from esys.escript.linearPDEs import Poisson, Helmholtz
+
+class Test_SplitWorld(unittest.TestCase):
+  """
+  Class to test splitworld functions.
+  Requires subclasses to supply self.domainpars which is a list of constructor function followed
+  by arguments.
+  eg:  if your domain is created with Rectangle(3,4), then your domainpars would be [Rectangle,3,4]
+  """
+  
+  
+  class PoissonJob1(Job):
+    def __init__(self, **kwargs):
+      super(PoissonJob1, self).__init__(**kwargs)
+    
+    def work(self):
+      x = self.domain.getX()
+      gammaD = whereZero(x[0])+whereZero(x[1])
+      # define PDE and get its solution u
+      mypde = Poisson(domain=self.domain)
+      mypde.setValue(f=1, q=gammaD)
+      u = mypde.getSolution()
+      self.exportValue("answer", Lsup(u))
+      return True
+
+  class PoissonJob(Job):
+    def __init__(self, **kwargs):
+      super(Test_SplitWorld.PoissonJob, self).__init__(**kwargs)
+    
+    def work(self):
+      x = self.domain.getX()
+      gammaD = whereZero(x[0])+whereZero(x[1])
+      # define PDE and get its solution u
+      mypde = Poisson(domain=self.domain)
+      mypde.setValue(f=self.jobid, q=gammaD)
+      u = Lsup(mypde.getSolution())	   # we won't actually export the value to make
+      self.exportValue("answer", self.jobid) # testing easier
+      return True
+      
+  class HelmholtzJob(Job):
+    def __init__(self, **kwargs):
+      super(Test_SplitWorld.HelmholtzJob, self).__init__(**kwargs)
+    
+    def work(self):
+      # define PDE and get its solution u
+      mypde = Helmholtz(domain=self.domain)
+      mypde.setValue(omega=self.jobid)
+      u = mypde.getSolution()
+      self.exportValue("hanswer", 2*self.jobid)
+      self.exportValue("v", self.jobid)
+      return True
+      
+  class InjectJob(Job):
+    """
+    Tests jobs taking parameters
+    """
+    def __init__(self, **kwargs):
+      super(Test_SplitWorld.InjectJob, self).__init__(**kwargs)
+      self.value=kwargs['val']
+      self.name=kwargs['name']
+    
+    def work(self):
+      """
+      Make use of values passed to constructor
+      """
+      self.exportValue(self.name, self.value)
+      return True      
+
+  class FactorJob(Job):
+    """
+    Tests jobs taking parameters
+    """
+    def __init__(self, **kwargs):
+      super(Test_SplitWorld.FactorJob, self).__init__(**kwargs)
+      self.divisor=kwargs['fact']
+    
+    def work(self):
+      """
+      Make use of values passed to constructor
+      """
+      z=self.importValue("value")
+      if (z%self.divisor==0):
+          self.exportValue("boolean", self.divisor)
+      return True 
+      
+      
+  class ThrowJob(Job):
+    """
+    Trigger various faults
+    """
+    def __init__(self, **kwargs):
+      super(Test_SplitWorld.ThrowJob, self).__init__(**kwargs)
+      self.faultnum=kwargs['fault']             #leaving this out will test error in constructor
+      
+    def work(self):
+      if self.faultnum==1:
+        return "zero"           # non-boolean return value
+      if self.faultnum==2:
+        z=self.importValue("missing")   # unannounced import
+        return True
+      if self.faultnum==3:
+        self.exportValue("missing",0)   # undeclared
+        return True
+      if self.faultnum==4:
+        self.exportValue("answer","answer")  # type-mismatch in export
+      return True
+
+  class DummyJob(Job):
+    """
+    Trigger various faults
+    """
+    def __init__(self, **kwargs):
+      super(Test_SplitWorld.DummyJob, self).__init__(**kwargs)
+      
+    def work(self):
+      return True      
+      
+      
+  def test_faults(self):
+      for x in range(1,5):
+        sw=SplitWorld(getMPISizeWorld())
+        buildDomains(sw,*self.domainpars)
+        addVariable(sw, "answer", makeScalarReducer, "MAX") 
+        addJob(sw, Test_SplitWorld.ThrowJob, fault=x)
+        self.assertRaises(RuntimeError, sw.runJobs)
+
+  @unittest.skipIf(getMPISizeWorld()>97, "Too many ranks for this test")
+  def test_factorjobs(self):
+      """
+      test importing, multiple phases, max as a flag
+      """
+      sw=SplitWorld(getMPISizeWorld())
+      buildDomains(sw,*self.domainpars)
+      addVariable(sw, "value", makeScalarReducer, "MAX")
+      addVariable(sw, "boolean", makeScalarReducer, "MAX")
+         # first we will load in a value to factorise
+         # Don't run this test with 99 or more processes
+      addJob(sw, Test_SplitWorld.InjectJob, name='value', val=101)      # Feed it a prime  
+      addJob(sw, Test_SplitWorld.InjectJob, name='boolean', val=0)              # so we have a value
+      sw.runJobs()
+      for x in range(2,getMPISizeWorld()+2):
+        addJob(sw, Test_SplitWorld.FactorJob, fact=x)
+      sw.runJobs()
+      self.assertEquals(sw.getDoubleVariable('boolean'),0)
+      sw.clearVariable('value')
+      sw.clearVariable('boolean')
+      addJob(sw, Test_SplitWorld.InjectJob, name='value', val=101)      # Feed it a prime  
+      addJob(sw, Test_SplitWorld.InjectJob, name='boolean', val=0)              # so we have a value
+      sw.runJobs()
+      sw.clearVariable("value")
+      
+        # Now test with a value which has a factor
+      addJob(sw, Test_SplitWorld.InjectJob, name='value', val=100)       # Feed it a prime  
+      addJob(sw, Test_SplitWorld.InjectJob, name='boolean', val=0)               # so we have a value
+      sw.runJobs()
+      m=0
+      for x in range(2,getMPISizeWorld()+2):
+        addJob(sw, Test_SplitWorld.FactorJob, fact=x)
+        if 100%x==0:
+          m=x
+      sw.runJobs()
+      self.assertEquals(sw.getDoubleVariable('boolean'),m)      
+      
+  def test_split_simple_solve(self):
+    """
+    Solve a single equation
+    """
+    sw=SplitWorld(getMPISizeWorld())
+    buildDomains(sw,*self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")
+    addJob(sw, Test_SplitWorld.PoissonJob)
+    sw.runJobs()
+    self.assertEquals(sw.getDoubleVariable("answer"),1)
+    
+  def test_split_simple_solve_multiple(self):
+    """
+    Solve a number of the same equation in one batch
+    """
+    sw=SplitWorld(getMPISizeWorld())
+    buildDomains(sw,*self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")
+        # this gives us 1 job per world
+    total=0
+    jobid=1
+    for x in range(0,getMPISizeWorld()):
+        addJob(sw, Test_SplitWorld.PoissonJob)
+        total+=jobid
+        jobid+=1
+    sw.runJobs()
+    self.assertEquals(sw.getDoubleVariable("answer"), total)
+    
+  def test_split_simple_and_dummy(self):
+    """
+    Solve a number of the same equation with some worlds doing dummy Jobs
+    """
+    sw=SplitWorld(getMPISizeWorld())
+    buildDomains(sw,*self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")
+        # this gives us 1 job per world
+    total=0
+    mid=getMPISizeWorld()//2
+    if getMPISizeWorld()%2==1:
+      mid=mid+1
+    for x in range(0,mid):
+        addJob(sw, Test_SplitWorld.PoissonJob)
+        total=total+(x+1)
+    for x in range(0,mid):
+        addJob(sw, Test_SplitWorld.DummyJob)
+    sw.runJobs()
+      # expecting this to fail until I work out the answer
+    self.assertEqual(sw.getDoubleVariable("answer"), total)
+    
+  def test_split_simple_and_empty(self):
+    """
+    Solve a number of the same equation with some worlds doing nothing
+    """
+    sw=SplitWorld(getMPISizeWorld())
+    buildDomains(sw, *self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")
+        # this gives us at most 1 job per world
+    total=0    
+    mid=getMPISizeWorld()//2
+    if getMPISizeWorld()%2==1:
+      mid=mid+1    
+    for x in range(0,mid):
+        addJob(sw, Test_SplitWorld.PoissonJob)
+        total=total+(x+1)
+    sw.runJobs()
+      # expecting this to fail until I work out the answer
+    self.assertEquals(sw.getDoubleVariable("answer"),total)    
+    
+    
+  def test_split_multiple_batches(self):
+    """
+    Solve a number of the same equation in multiple batches
+    """
+    sw=SplitWorld(getMPISizeWorld())
+    buildDomains(sw,*self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")
+        # this gives us 1 job per world
+    total=0
+    sw.runJobs()
+    for x in range(0,getMPISizeWorld()):
+        addJob(sw, Test_SplitWorld.PoissonJob)
+        total=total+x
+    sw.runJobs()
+    sw.runJobs()
+    sw.clearVariable("answer")
+    total=0
+    for x in range(0,getMPISizeWorld()):
+        addJob(sw, Test_SplitWorld.PoissonJob)
+        total=total+(x+1+getMPISizeWorld())
+    sw.runJobs()
+      # expecting this to fail until I work out the answer
+    self.assertEquals(sw.getDoubleVariable("answer"),total)    
+  
+  @unittest.skipIf(getMPISizeWorld()%2!=0, "Test requires even number of processes")
+  def test_multiple_equations_size2world(self):
+    """
+    Test two different types of equations to solve mixed in batches
+    We will try various combinations to spread them out over the 
+    worlds in different patterns.
+    This version attempts this with worlds of size 2
+    """
+    wc=getMPISizeWorld()//2
+    sw=SplitWorld(wc)
+    buildDomains(sw, *self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")   
+    addVariable(sw, "hanswer", makeScalarReducer, "SUM")  
+    addVariable(sw, "v", makeScalarReducer, "MAX")
+    
+    tot=0
+    jobid=1
+       #first put jobs of the same type close.
+    for x in range(0, max(wc//3,1)):
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1
+    for x in range(0, max(wc//3,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*(jobid)
+      jobid+=1
+    for x in range(0, max(wc//3,1)):
+      addJob(sw, Test_SplitWorld.DummyJob)
+      jobid+=1
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)
+    sw.clearVariable("answer")
+    sw.clearVariable("hanswer")
+    sw.clearVariable("v")
+    tot=0
+      # similar but separated by dummy Jobs
+    for x in range(0, max(wc//3,1)):
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1
+    for x in range(0, max(wc//3,1)):
+      addJob(sw, Test_SplitWorld.DummyJob)      
+      jobid+=1
+    for x in range(0, max(wc//3,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      jobid+=1
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)
+    sw.clearVariable("answer")
+    sw.clearVariable("hanswer")
+    sw.clearVariable("v")   
+      # mixed
+    tot=0
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      addJob(sw, Test_SplitWorld.DummyJob)
+      jobid+=2
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)    
+
+  @unittest.skipIf(getMPISizeWorld()%4!=0, "Test requires number of processes divisible by 4")
+  def test_multiple_equations_size4world(self):
+    """
+    Test two different types of equations to solve mixed in batches
+    We will try various combinations to spread them out over the 
+    worlds in different patterns.
+    This version attempts this with worlds of size 2
+    """
+    wc=getMPISizeWorld()//4
+    sw=SplitWorld(wc)
+    buildDomains(sw,*self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")   
+    addVariable(sw, "hanswer", makeScalarReducer, "SUM")  
+    addVariable(sw, "v", makeScalarReducer, "MAX")
+    
+    jobid=1
+    tot=0
+       #first put jobs of the same type close.
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      jobid+=1      
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.DummyJob)
+      jobid+=1
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)
+    sw.clearVariable("answer")
+    sw.clearVariable("hanswer")
+    sw.clearVariable("v")
+    tot=0
+      # similar but separated by dummy Jobs
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1      
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.DummyJob) 
+      jobid+=1     
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      jobid+=1
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)
+    sw.clearVariable("answer")
+    sw.clearVariable("hanswer")
+    sw.clearVariable("v")   
+    tot=0
+      # mixed
+    for x in range(0, max(wc//2,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      jobid+=1
+      addJob(sw, Test_SplitWorld.DummyJob)
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=2
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)        
+    
+    
+  def test_multiple_equations_smallworld(self):
+    """
+    Test two different types of equations to solve mixed in batches
+    We will try various combinations to spread them out over the 
+    worlds in different patterns
+    """
+    sw=SplitWorld(getMPISizeWorld())
+    buildDomains(sw,*self.domainpars)
+    addVariable(sw, "answer", makeScalarReducer, "SUM")   
+    addVariable(sw, "hanswer", makeScalarReducer, "SUM")  
+    addVariable(sw, "v", makeScalarReducer, "MAX")
+    
+    tot=0
+    jobid=1
+       #first put jobs of the same type close together.
+    for x in range(0,max(getMPISizeWorld()//3,1)):
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1
+    for x in range(0,max(getMPISizeWorld()//3,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      jobid+=1
+    for x in range(0,getMPISizeWorld()//3):
+      addJob(sw, Test_SplitWorld.DummyJob)
+      jobid+=1
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)
+    sw.clearVariable("answer")
+    sw.clearVariable("hanswer")
+    sw.clearVariable("v")
+    tot=0
+      # similar but separated by dummy Jobs
+    for x in range(0,max(getMPISizeWorld()//3,1)):
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=1
+    for x in range(0,getMPISizeWorld()//3):
+      addJob(sw, Test_SplitWorld.DummyJob)      
+      jobid+=1      
+    for x in range(0,max(getMPISizeWorld()//3,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=2*jobid
+      jobid+=1      
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)
+    sw.clearVariable("answer")
+    sw.clearVariable("hanswer")
+    sw.clearVariable("v")   
+    tot=0
+      # mixed
+    for x in range(0, max(getMPISizeWorld()//2,1)):
+      addJob(sw, Test_SplitWorld.HelmholtzJob)
+      tot+=jobid*2
+      addJob(sw, Test_SplitWorld.DummyJob)
+      addJob(sw, Test_SplitWorld.PoissonJob)
+      jobid+=3
+    sw.runJobs()
+    ha=sw.getDoubleVariable("hanswer")
+    self.assertEquals(ha, tot)     
diff --git a/escriptcore/test/python/test_symfuncs.py b/escriptcore/test/python/test_symfuncs.py
index 12daf26..8dcf080 100644
--- a/escriptcore/test/python/test_symfuncs.py
+++ b/escriptcore/test/python/test_symfuncs.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util.py b/escriptcore/test/python/test_util.py
index cf9ab4d..946d1d2 100644
--- a/escriptcore/test/python/test_util.py
+++ b/escriptcore/test/python/test_util.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_base.py b/escriptcore/test/python/test_util_base.py
index 82f89a1..ec45540 100644
--- a/escriptcore/test/python/test_util_base.py
+++ b/escriptcore/test/python/test_util_base.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -56,13 +56,16 @@ class Test_util_base(unittest.TestCase):
 #=========================================================
 #  File writer
 #=========================================================
+   def setup(self):
+        self.workdir=ESCRIPT_WORKDIR
+
    def __checkContent(self,fn,ref_cont):
         cont=open(fn,'r').readlines()
         self.assertTrue(len(cont)==len(ref_cont),"wrong number of records")
         for i in range(len(cont)):
            self.assertTrue(cont[i].strip()==ref_cont[i],"wrong records %s"%i)
    def test_FileWriter_W(self):
-        fn=os.path.join(ESCRIPT_WORKDIR, "filewriter_w.txt")
+        fn=os.path.join(self.workdir, "filewriter_w.txt")
         self.assertRaises(IOError,FileWriter,fn="",append=False)
         f=FileWriter(fn,append=False)
         self.assertTrue(f.name==fn, "wrong file name.")
@@ -80,7 +83,7 @@ class Test_util_base(unittest.TestCase):
         if getMPIRankWorld()==0: os.unlink(fn)
 
    def test_FileWriter_A(self):
-        fn=os.path.join(ESCRIPT_WORKDIR, "filewriter_a.txt")
+        fn=os.path.join(self.workdir, "filewriter_a.txt")
         if getMPIRankWorld()==0: open(fn,'w').write("line1"+os.linesep)
         self.assertRaises(IOError,FileWriter,fn="",append=True)
         f=FileWriter(fn,append=True)
@@ -99,7 +102,7 @@ class Test_util_base(unittest.TestCase):
         if getMPIRankWorld()==0: os.unlink(fn)
 
    def test_FileWriter_A_loc(self):
-        fn=os.path.join(ESCRIPT_WORKDIR, "filewriter_a_loc.txt")
+        fn=os.path.join(self.workdir, "filewriter_a_loc.txt")
         if getMPIRankWorld()>0:
             fn2=fn+".%s"%getMPIRankWorld()
         else:
@@ -121,7 +124,7 @@ class Test_util_base(unittest.TestCase):
         os.unlink(fn2)
 
    def test_FileWriter_W_loc(self):
-        fn=os.path.join(ESCRIPT_WORKDIR, "filewriter_w_loc.txt")
+        fn=os.path.join(self.workdir, "filewriter_w_loc.txt")
         if getMPIRankWorld()>0:
             fn2=fn+".%s"%getMPIRankWorld()
         else:
diff --git a/escriptcore/test/python/test_util_binary_no_tagged_data.py b/escriptcore/test/python/test_util_binary_no_tagged_data.py
index 62e9b4d..d1bde59 100644
--- a/escriptcore/test/python/test_util_binary_no_tagged_data.py
+++ b/escriptcore/test/python/test_util_binary_no_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_binary_with_tagged_data.py b/escriptcore/test/python/test_util_binary_with_tagged_data.py
index 5386c3f..9e93484 100644
--- a/escriptcore/test/python/test_util_binary_with_tagged_data.py
+++ b/escriptcore/test/python/test_util_binary_with_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_overloaded_binary_no_tagged_data.py b/escriptcore/test/python/test_util_overloaded_binary_no_tagged_data.py
index b18a57b..79c8288 100644
--- a/escriptcore/test/python/test_util_overloaded_binary_no_tagged_data.py
+++ b/escriptcore/test/python/test_util_overloaded_binary_no_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_overloaded_binary_with_tagged_data.py b/escriptcore/test/python/test_util_overloaded_binary_with_tagged_data.py
index 365b723..4a8c28e 100644
--- a/escriptcore/test/python/test_util_overloaded_binary_with_tagged_data.py
+++ b/escriptcore/test/python/test_util_overloaded_binary_with_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_reduction_no_tagged_data.py b/escriptcore/test/python/test_util_reduction_no_tagged_data.py
index 0dbd113..9550e9a 100644
--- a/escriptcore/test/python/test_util_reduction_no_tagged_data.py
+++ b/escriptcore/test/python/test_util_reduction_no_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_reduction_with_tagged_data.py b/escriptcore/test/python/test_util_reduction_with_tagged_data.py
index 927a904..78e1a52 100644
--- a/escriptcore/test/python/test_util_reduction_with_tagged_data.py
+++ b/escriptcore/test/python/test_util_reduction_with_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_slicing_no_tagged_data.py b/escriptcore/test/python/test_util_slicing_no_tagged_data.py
index 4aeeb34..e5b3eb5 100644
--- a/escriptcore/test/python/test_util_slicing_no_tagged_data.py
+++ b/escriptcore/test/python/test_util_slicing_no_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_slicing_with_tagged_data.py b/escriptcore/test/python/test_util_slicing_with_tagged_data.py
index d85ddc7..ccac09d 100644
--- a/escriptcore/test/python/test_util_slicing_with_tagged_data.py
+++ b/escriptcore/test/python/test_util_slicing_with_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_spatial_functions1.py b/escriptcore/test/python/test_util_spatial_functions1.py
index cf47ad6..c423e4b 100644
--- a/escriptcore/test/python/test_util_spatial_functions1.py
+++ b/escriptcore/test/python/test_util_spatial_functions1.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_spatial_functions2.py b/escriptcore/test/python/test_util_spatial_functions2.py
index 4556103..723bb99 100644
--- a/escriptcore/test/python/test_util_spatial_functions2.py
+++ b/escriptcore/test/python/test_util_spatial_functions2.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_spatial_functions3.py b/escriptcore/test/python/test_util_spatial_functions3.py
index e7080f5..809442a 100644
--- a/escriptcore/test/python/test_util_spatial_functions3.py
+++ b/escriptcore/test/python/test_util_spatial_functions3.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_unary_no_tagged_data.py b/escriptcore/test/python/test_util_unary_no_tagged_data.py
index 2af67ad..a488497 100644
--- a/escriptcore/test/python/test_util_unary_no_tagged_data.py
+++ b/escriptcore/test/python/test_util_unary_no_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/test_util_unary_with_tagged_data.py b/escriptcore/test/python/test_util_unary_with_tagged_data.py
index d8cb6dd..e18a7ec 100644
--- a/escriptcore/test/python/test_util_unary_with_tagged_data.py
+++ b/escriptcore/test/python/test_util_unary_with_tagged_data.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/esysUtils/src/EsysAssert.h b/esysUtils/src/EsysAssert.h
index b0966bb..5d27766 100644
--- a/esysUtils/src/EsysAssert.h
+++ b/esysUtils/src/EsysAssert.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/EsysAssertException.cpp b/esysUtils/src/EsysAssertException.cpp
index aadde0f..6df2f9c 100644
--- a/esysUtils/src/EsysAssertException.cpp
+++ b/esysUtils/src/EsysAssertException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/EsysAssertException.h b/esysUtils/src/EsysAssertException.h
index 11fe08a..4d3aff0 100644
--- a/esysUtils/src/EsysAssertException.h
+++ b/esysUtils/src/EsysAssertException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/EsysException.cpp b/esysUtils/src/EsysException.cpp
index a71d29b..c871287 100644
--- a/esysUtils/src/EsysException.cpp
+++ b/esysUtils/src/EsysException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/EsysException.h b/esysUtils/src/EsysException.h
index cc242bf..f65f675 100644
--- a/esysUtils/src/EsysException.h
+++ b/esysUtils/src/EsysException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/EsysRandom.cpp b/esysUtils/src/EsysRandom.cpp
index 47e4eb8..37b0c5e 100644
--- a/esysUtils/src/EsysRandom.cpp
+++ b/esysUtils/src/EsysRandom.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2013-2014 by University of Queensland
+* Copyright (c) 2013-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/EsysRandom.h b/esysUtils/src/EsysRandom.h
index 5e05e40..977b5e0 100644
--- a/esysUtils/src/EsysRandom.h
+++ b/esysUtils/src/EsysRandom.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2013-2014 by University of Queensland
+* Copyright (c) 2013-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/Esys_MPI.cpp b/esysUtils/src/Esys_MPI.cpp
index 7bcb953..bf18999 100644
--- a/esysUtils/src/Esys_MPI.cpp
+++ b/esysUtils/src/Esys_MPI.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -18,7 +18,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-
+#include <vector>
 
 #include "Esys_MPI.h"
 #include "index.h"
@@ -27,7 +27,7 @@
 #include "EsysException.h"
 
 
-#include <iostream>	// temp for debugging
+#include <iostream>        // temp for debugging
 
 namespace esysUtils
 {
@@ -36,7 +36,7 @@ JMPI makeInfo(MPI_Comm comm, bool owncom)
 {
     if (esysUtils::NoCOMM_WORLD::active() && comm==MPI_COMM_WORLD)
     {
-	throw esysUtils::EsysException("Attempt to use the MPI_COMM_WORLD communicator when it is blocked.");
+        throw esysUtils::EsysException("Attempt to use the MPI_COMM_WORLD communicator when it is blocked.");
     }
     JMPI_* p=new JMPI_(comm, owncom);
     return JMPI(p);
@@ -44,18 +44,18 @@ JMPI makeInfo(MPI_Comm comm, bool owncom)
 
 
 JMPI_::JMPI_(MPI_Comm mpicomm, bool owncom)
-	: comm(mpicomm), ownscomm(owncom)
+        : comm(mpicomm), ownscomm(owncom)
 {
-	msg_tag_counter = 0;
+        msg_tag_counter = 0;
 #ifdef ESYS_MPI
-	if (MPI_Comm_rank(comm, &rank)!=MPI_SUCCESS || MPI_Comm_size(comm, &size)!=MPI_SUCCESS)
-	{
-	    Esys_setError( ESYS_MPI_ERROR, "Esys_MPIInfo_alloc : error finding comm rank/size" );
-	}
+        if (MPI_Comm_rank(comm, &rank)!=MPI_SUCCESS || MPI_Comm_size(comm, &size)!=MPI_SUCCESS)
+        {
+            Esys_setError( ESYS_MPI_ERROR, "Esys_MPIInfo_alloc : error finding comm rank/size" );
+        }
 #else
-	rank=0;
-	size=1;	
-#endif	
+        rank=0;
+        size=1;        
+#endif        
 }
 
 JMPI_::~JMPI_()
@@ -63,7 +63,7 @@ JMPI_::~JMPI_()
 #ifdef ESYS_MPI
     if (ownscomm)
     {
-	MPI_Comm_free(&comm);
+        MPI_Comm_free(&comm);
     }
 #endif
 }
@@ -168,7 +168,7 @@ bool esysUtils::Esys_MPIInfo_noError( const esysUtils::JMPI& mpi_info )
   int errorGlobal = errorLocal;
 
 #ifdef ESYS_MPI
-  if (!checkResult(errorLocal, errorGlobal, mpi_info->comm))
+  if (!checkResult(errorLocal, errorGlobal, mpi_info))
   {
       return false;
   }
@@ -181,25 +181,82 @@ bool esysUtils::Esys_MPIInfo_noError( const esysUtils::JMPI& mpi_info )
   return (errorGlobal==0);
 }
 
-/* returns the max of inputs on all ranks -- or just sends the input back on nompi */
-bool esysUtils::checkResult(int& input, int& output, MPI_Comm& comm)
+// Throw all values in and get the maximum --- used for error checking.
+// This used to be implemented as a simple AllReduce.
+// However, if there are other (overlapping) communicators in the system, they don't
+// react well to getting unexpected/untagged messages.
+// To avoid this, we do individual sends to the root which sends the result back.
+bool esysUtils::checkResult(int res, int& mres, const esysUtils::JMPI& info)
 {
+    if (info->size==1)
+    {
+        mres=res;
+        return true;
+    }
 #ifdef ESYS_MPI
-    output=0;
-    if (MPI_Allreduce(&input, &output, 1, MPI_INT, MPI_MAX, comm)!=MPI_SUCCESS)
+    const int leader=0;
+    const int BIGTAG=esysUtils::getSubWorldTag();
+    if (info->rank!=leader)
+    {  
+        if (MPI_Send(&res, 1, MPI_INT, leader, BIGTAG, info->comm)!=MPI_SUCCESS)
+            return false;
+        MPI_Status status;
+        if (MPI_Recv(&mres, 1, MPI_INT, leader, BIGTAG, info->comm, &status)!=MPI_SUCCESS)
+            return false;
+    }
+    else
     {
-	return false;
+        std::vector<MPI_Status> status(info->size - 1);
+        MPI_Request* reqs=new MPI_Request[info->size-1];
+        int* eres=new int[info->size-1];
+        for (int i=0;i<info->size-1;++i)
+        {
+            MPI_Irecv(eres+i, 1, MPI_INT, i+1, BIGTAG, info->comm, reqs+i);          
+        }  
+        if (MPI_Waitall(info->size-1, reqs, &status[0])!=MPI_SUCCESS)
+        {
+            delete[] reqs;
+            delete[] eres;
+            return false;
+        }
+        // now we have them all, find the max
+        mres=res;
+        for (int i=0;i<info->size-1;++i)
+        {
+            if (mres<eres[i])
+            {
+                mres=eres[i];
+            }
+        }
+        delete[] eres;
+        // now we know what the result should be
+        // send it to the others
+        for (int i=0;i<info->size-1;++i)
+        {
+            MPI_Isend(&mres, 1, MPI_INT, i+1, BIGTAG, info->comm, reqs+i);          
+        }
+        if (MPI_Waitall(info->size-1, reqs, &status[0])!=MPI_SUCCESS)
+        {
+            delete[] reqs;
+            return false;
+        }
+        delete[] reqs;
+      
     }
-    return true;
-#else
-    output=input;
-    return true;
 #endif
+    return true;
 }
 
 
 
 
+
+
+
+
+
+
+
 // ensure that the any ranks with an empty src argument end up with the string from
 // one of the other ranks
 // with no-mpi, it makes dest point at a copy of src
@@ -211,7 +268,7 @@ bool esysUtils::shipString(const char* src, char** dest, MPI_Comm& comm)
     Esys_MPI_rank rank=0;
     if (MPI_Comm_rank( comm, &rank )!=MPI_SUCCESS)
     {
-	return false;	// we have no reason to believe MPI works anymore
+        return false;        // we have no reason to believe MPI works anymore
     }
     
     int slen=strlen(src);
@@ -222,44 +279,44 @@ bool esysUtils::shipString(const char* src, char** dest, MPI_Comm& comm)
     int out;
     if (MPI_Allreduce(&in, &out, 1, MPI_INT, MPI_MAX, comm)!=MPI_SUCCESS)
     {
-	return false;
+        return false;
     }
-    if (out==-1)		// should not be called under these conditions, but noone had a string
+    if (out==-1)                // should not be called under these conditions, but noone had a string
     {
-	*dest=new char[1];
-	*dest[0]='\0';
-	return true;
+        *dest=new char[1];
+        *dest[0]='\0';
+        return true;
     }
     // since we will be using broadcast, we need to tell everyone how big the string is going to be
     // with an additional bcast
     
     if (MPI_Bcast(&slen, 1, MPI_INT, out, comm)!=MPI_SUCCESS)
     {
-	return false;
+        return false;
     }
     // now broadcast that string to everyone
     if (rank==out)
     {
-	// I could const _ cast src but instead I'll make a copy
-	
-	*dest=new char[slen+1];
-	strcpy(*dest, src);
-	
-	// this guy should just send the string
-	if (MPI_Bcast(*dest, slen+1, MPI_CHAR, out, comm)!=MPI_SUCCESS)
-	{
-	    return false;
-	}
-	return true;
+        // I could const _ cast src but instead I'll make a copy
+        
+        *dest=new char[slen+1];
+        strcpy(*dest, src);
+        
+        // this guy should just send the string
+        if (MPI_Bcast(*dest, slen+1, MPI_CHAR, out, comm)!=MPI_SUCCESS)
+        {
+            return false;
+        }
+        return true;
     }
     else
     {
-	*dest=new char[slen+1];
-	if (MPI_Bcast(*dest, slen+1, MPI_CHAR, out, comm)!=MPI_SUCCESS)
-	{
-	    return false;
-	}
-	return true;
+        *dest=new char[slen+1];
+        if (MPI_Bcast(*dest, slen+1, MPI_CHAR, out, comm)!=MPI_SUCCESS)
+        {
+            return false;
+        }
+        return true;
     }
 #else
     *dest=new char[strlen(src)+1];
@@ -279,7 +336,7 @@ esysUtils::NoCOMM_WORLD::NoCOMM_WORLD()
 {
     if (nocommworldplease)
     {
-	throw EsysException("NoCOMM_WORLD does not nest.");
+        throw EsysException("NoCOMM_WORLD does not nest.");
     }
     nocommworldplease=true;
 }
diff --git a/esysUtils/src/Esys_MPI.h b/esysUtils/src/Esys_MPI.h
index c34c5dc..d3840b5 100644
--- a/esysUtils/src/Esys_MPI.h
+++ b/esysUtils/src/Esys_MPI.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -47,6 +47,8 @@
 // MPI_Op replacements for non-MPI - these values are arbitrary
 
    #define MPI_SUM 100
+   #define MPI_MIN 101
+   #define MPI_MAX 102
 
 // end MPI_op
 
@@ -70,7 +72,7 @@ namespace esysUtils {
 ESYSUTILS_DLL_API
 inline int getSubWorldTag()	
 {
-    return ('S'<< 24) + ('u' << 16) + ('b' << 8) + 'W';  
+    return (('S'<< 24) + ('u' << 16) + ('b' << 8) + 'W')%1010201;
 }
   
 class JMPI_;
@@ -134,9 +136,13 @@ inline std::string appendRankToFileName(const std::string &fileName,
 // ensure that the any ranks with an empty src argument end up with the string from
 // one of the other ranks
 // with no-mpi, it makes dest point at a copy of src
+ESYSUTILS_DLL_API
 bool shipString(const char* src, char** dest, MPI_Comm& comm);
 
-bool checkResult(int& input, int& output, MPI_Comm& comm);
+
+// Everyone puts in their error code and everyone gets the largest one
+ESYSUTILS_DLL_API
+bool checkResult(int input, int& output, const JMPI& comm);
 
 
 // Do not cope with nested calls
diff --git a/esysUtils/src/IndexList.h b/esysUtils/src/IndexList.h
index a176b7d..07904a0 100644
--- a/esysUtils/src/IndexList.h
+++ b/esysUtils/src/IndexList.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/SConscript b/esysUtils/src/SConscript
index 893ad89..b6190da 100644
--- a/esysUtils/src/SConscript
+++ b/esysUtils/src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -25,6 +25,7 @@ sources = """
     error.cpp
     esysExceptionTranslator.cpp
     blocktimer.cpp
+    pyerr.cpp
 """.split()
 
 headers = """
@@ -41,7 +42,9 @@ headers = """
     mem.h
     index.h
     maths.h
+    pyerr.h
     system_dep.h
+    first.h
     types.h
 """.split()
 
diff --git a/esysUtils/src/blocktimer.cpp b/esysUtils/src/blocktimer.cpp
index 037b272..c41d11f 100644
--- a/esysUtils/src/blocktimer.cpp
+++ b/esysUtils/src/blocktimer.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/blocktimer.h b/esysUtils/src/blocktimer.h
index 688df3d..4fb1dda 100644
--- a/esysUtils/src/blocktimer.h
+++ b/esysUtils/src/blocktimer.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/error.cpp b/esysUtils/src/error.cpp
index e8ead61..041d998 100644
--- a/esysUtils/src/error.cpp
+++ b/esysUtils/src/error.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2010-2014 by University of Queensland
+* Copyright (c) 2010-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/error.h b/esysUtils/src/error.h
index b71700b..39f0259 100644
--- a/esysUtils/src/error.h
+++ b/esysUtils/src/error.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2010-2014 by University of Queensland
+* Copyright (c) 2010-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/esysExceptionTranslator.cpp b/esysUtils/src/esysExceptionTranslator.cpp
index 1e037e8..dd24bd3 100644
--- a/esysUtils/src/esysExceptionTranslator.cpp
+++ b/esysUtils/src/esysExceptionTranslator.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,7 +14,8 @@
 *
 *****************************************************************************/
 
-
+#define ESNEEDPYTHON
+#include "first.h"
 #include "system_dep.h"
 #include "esysExceptionTranslator.h" 
 #include <iostream>
diff --git a/esysUtils/src/esysExceptionTranslator.h b/esysUtils/src/esysExceptionTranslator.h
index 38e15e6..40d0437 100644
--- a/esysUtils/src/esysExceptionTranslator.h
+++ b/esysUtils/src/esysExceptionTranslator.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/esysFileWriter.h b/esysUtils/src/esysFileWriter.h
index f4a5263..d7219ed 100644
--- a/esysUtils/src/esysFileWriter.h
+++ b/esysUtils/src/esysFileWriter.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/escriptcore/src/UtilC.h b/esysUtils/src/first.h
similarity index 70%
copy from escriptcore/src/UtilC.h
copy to esysUtils/src/first.h
index 367ed03..d1eb9c8 100644
--- a/escriptcore/src/UtilC.h
+++ b/esysUtils/src/first.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,12 +14,13 @@
 *
 *****************************************************************************/
 
+/* The purpose is to gather anything which "needs to be first include" */
 
-#if !defined  escript_UtilC_20040611_H
-#define escript_UtilC_20040611_H
-#include "system_dep.h"
-#include "SolverOptions.h"
+#ifndef esysutils_first_h
+#define esysutils_first_h
 
-#define ESCRIPT_MAX_DATA_RANK 4
+#ifdef ESNEEDPYTHON
+#include "Python.h"
+#endif
 
 #endif
diff --git a/esysUtils/src/index.h b/esysUtils/src/index.h
index ddfcb8f..fe2edd0 100644
--- a/esysUtils/src/index.h
+++ b/esysUtils/src/index.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/maths.h b/esysUtils/src/maths.h
index 4a88efb..9b72304 100644
--- a/esysUtils/src/maths.h
+++ b/esysUtils/src/maths.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,36 +20,8 @@
 
 /************************************************************************************/
 
-/*    Pull in a maths library and define ISNAN      */
-
-
-/* some system values */
-/* FIXME: This is not satisfactory.                                */
-/* _ECC, __INTEL_COMPILER, and other                               */
-/* intel compiler pre-defines need to be handled                   */
-/* (__ICL, __ICC come to mind)                                     */
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-#include <mathimf.h>
-#else
+/*    Pull in a maths library */
 #include <cmath>
-#endif
-
-/*#ifndef NAN
-   #define NAN (0.0/0.0)
-#endif
-*/
-/*#define IS_NAN(__VAL__)  ( (__VAL__) == NAN )*/  /* this does not work */
-/* #define IS_NAN(__VAL__)  ( ! ( ( (__VAL__) >= 0. ) ||  ( (__VAL__) <= 0. ) ) )  this does not work */
-
-#ifdef isnan
-  #define IS_NAN(__VAL__) (isnan(__VAL__))
-#elif defined _isnan
-  #define IS_NAN(__VAL__) (_isnan(__VAL__))
-#else
-  // This is not guaranteed to work if the optimiser thinks it can optimise this check away
-  #define IS_NAN(__VAL__) (!((__VAL__)==(__VAL__)))
-#endif
-
 
 #define EPSILON DBL_EPSILON
 #define LARGE_POSITIVE_FLOAT DBL_MAX
diff --git a/esysUtils/src/mem.h b/esysUtils/src/mem.h
index f505f3b..74eb702 100644
--- a/esysUtils/src/mem.h
+++ b/esysUtils/src/mem.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/src/pyerr.cpp b/esysUtils/src/pyerr.cpp
new file mode 100644
index 0000000..be8ea2a
--- /dev/null
+++ b/esysUtils/src/pyerr.cpp
@@ -0,0 +1,45 @@
+/*****************************************************************************
+*
+* Copyright (c) 2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "first.h"
+#include "pyerr.h"
+
+// Function factored out of SubWorld code
+
+void getStringFromPyException(boost::python::error_already_set e, std::string& errormsg)
+{
+	using namespace boost::python;
+  	PyObject* ptype=0;
+ 	PyObject* pvalue=0;
+ 	PyObject* ptraceback=0;
+ 	PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+	PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
+ 
+	PyObject* errobj=PyObject_Str(pvalue);
+
+#ifdef ESPYTHON3	
+	PyObject* rr=PyUnicode_AsASCIIString(errobj);
+	errormsg=PyBytes_AsString(rr);
+	Py_XDECREF(rr);
+#else
+	errormsg=PyString_AsString(errobj);
+#endif
+	Py_XDECREF(errobj);
+
+	Py_XDECREF(ptype);
+	Py_XDECREF(pvalue);
+	Py_XDECREF(ptraceback);
+}
diff --git a/escriptcore/src/UtilC.h b/esysUtils/src/pyerr.h
similarity index 63%
copy from escriptcore/src/UtilC.h
copy to esysUtils/src/pyerr.h
index 367ed03..64ce9c9 100644
--- a/escriptcore/src/UtilC.h
+++ b/esysUtils/src/pyerr.h
@@ -1,7 +1,6 @@
-
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,12 +13,16 @@
 *
 *****************************************************************************/
 
+// Function factored out of SubWorld code
+#ifndef ESPYERR_H
+#define ESPYERR_H
 
-#if !defined  escript_UtilC_20040611_H
-#define escript_UtilC_20040611_H
+#include <string>
 #include "system_dep.h"
-#include "SolverOptions.h"
+#include "types.h"
+#include "boost/python/errors.hpp"
 
-#define ESCRIPT_MAX_DATA_RANK 4
+ESYSUTILS_DLL_API
+void getStringFromPyException(boost::python::error_already_set e, std::string& errormsg);
 
-#endif
+#endif
\ No newline at end of file
diff --git a/esysUtils/src/system_dep.h b/esysUtils/src/system_dep.h
index 5ac02db..cf3acf7 100644
--- a/esysUtils/src/system_dep.h
+++ b/esysUtils/src/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,16 +26,7 @@
 #ifndef esysutils_system_dep_h
 #define esysutils_system_dep_h
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/* The Intel compiler on windows has an "improved" math library compared to the usual Visual C++ one
-* In particular it has a acosh and other similar functions which aren't implemented in Visual C++ math.h
-* Note you will get a compile time error if any other header (including system ones) include math.h before mathimf.h
-* has been included. As a result system_dep.h must be included FIRST at all times (this prevents math.h from being included).
-*/
-#include <mathimf.h>
-#else
 #include <cmath>
-#endif
 
 #define ESYSUTILS_DLL_API
 
@@ -64,15 +55,4 @@
 
 #define NO_ARG
 
-/* you'll need this one day. */
-#ifndef __const
-# if (defined __STDC__ && __STDC__) || defined __cplusplus
-#  define __const	const
-# else
-#  define __const
-# endif
-#endif
-
-
-
 #endif
diff --git a/esysUtils/src/types.h b/esysUtils/src/types.h
index b1c778f..f6179be 100644
--- a/esysUtils/src/types.h
+++ b/esysUtils/src/types.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2010-2014 by University of Queensland
+* Copyright (c) 2010-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/test/EsysExceptionTestCase.cpp b/esysUtils/test/EsysExceptionTestCase.cpp
index 435cc03..3eec5fa 100644
--- a/esysUtils/test/EsysExceptionTestCase.cpp
+++ b/esysUtils/test/EsysExceptionTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/test/EsysExceptionTestCase.h b/esysUtils/test/EsysExceptionTestCase.h
index d3ed4b7..98b0065 100644
--- a/esysUtils/test/EsysExceptionTestCase.h
+++ b/esysUtils/test/EsysExceptionTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/test/EsysFileWriterTestCase.cpp b/esysUtils/test/EsysFileWriterTestCase.cpp
index 7966d0c..8082482 100644
--- a/esysUtils/test/EsysFileWriterTestCase.cpp
+++ b/esysUtils/test/EsysFileWriterTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/test/EsysFileWriterTestCase.h b/esysUtils/test/EsysFileWriterTestCase.h
index b0eb3a8..46925c4 100644
--- a/esysUtils/test/EsysFileWriterTestCase.h
+++ b/esysUtils/test/EsysFileWriterTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/esysUtils/test/SConscript b/esysUtils/test/SConscript
index 602bddc..44b1cab 100644
--- a/esysUtils/test/SConscript
+++ b/esysUtils/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/esysUtils/test/esysUtils_UnitTest.cpp b/esysUtils/test/esysUtils_UnitTest.cpp
index 2b8144a..a5033d9 100644
--- a/esysUtils/test/esysUtils_UnitTest.cpp
+++ b/esysUtils/test/esysUtils_UnitTest.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/benchmarks/finleybench.py b/finley/benchmarks/finleybench.py
index d053143..2a8be13 100644
--- a/finley/benchmarks/finleybench.py
+++ b/finley/benchmarks/finleybench.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/benchmarks/runbenchmark.py b/finley/benchmarks/runbenchmark.py
index bfc39cd..82b7cc2 100755
--- a/finley/benchmarks/runbenchmark.py
+++ b/finley/benchmarks/runbenchmark.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/py_src/SConscript b/finley/py_src/SConscript
index 4681239..0d6fa16 100644
--- a/finley/py_src/SConscript
+++ b/finley/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/finley/py_src/__init__.py b/finley/py_src/__init__.py
index 65f8ad8..2f30c7f 100644
--- a/finley/py_src/__init__.py
+++ b/finley/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@
 """Our most general domain representation. Imports submodules into its namespace
 """
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/py_src/factorywrappers.py b/finley/py_src/factorywrappers.py
index c6b2f43..6b5a798 100644
--- a/finley/py_src/factorywrappers.py
+++ b/finley/py_src/factorywrappers.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2011-2014 by University of Queensland
+# Copyright (c) 2011-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2011-2014 by University of Queensland
+__copyright__="""Copyright (c) 2011-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -39,7 +39,7 @@ def ReadMesh(filename, integrationOrder=-1, reducedIntegrationOrder=-1, optimize
       args+=[None]
     return __ReadMesh_driver(args)
   
-  
+ReadMesh.__doc__=__ReadMesh_driver.__doc__  
   
 def ReadGmsh(fileName, numDim, integrationOrder=-1, reducedIntegrationOrder=-1, optimize=True,  
       useMacroElements=False, **kwargs):
@@ -57,6 +57,8 @@ def ReadGmsh(fileName, numDim, integrationOrder=-1, reducedIntegrationOrder=-1,
       args+=[None]
     return __ReadGmsh_driver(args)      
 
+ReadGmsh.__doc__=__ReadGmsh_driver.__doc__
+
 
 def Rectangle(n0=1, n1=1, order=1, l0=1.0, l1=1.0, periodic0=False, periodic1=False, integrationOrder=-1, 
       reducedIntegrationOrder=-1, useElementsOnFace=None, useFullElementOrder=0, optimize=0, **kwargs):
@@ -80,6 +82,8 @@ def Rectangle(n0=1, n1=1, order=1, l0=1.0, l1=1.0, periodic0=False, periodic1=Fa
       args+=[None]
     return __Rectangle_driver(args)
 
+Rectangle.__doc__=__Rectangle_driver.__doc__
+
 def Brick(n0=1, n1=1, n2=1, order=1, l0=1.0, l1=1.0, l2=1.0, periodic0=0, periodic1=0, periodic2=0,
     integrationOrder=-1, reducedIntegrationOrder=-1, useElementsOnFace=1, useFullElementOrder=0,
     optimize=0, **kwargs):
@@ -103,3 +107,5 @@ def Brick(n0=1, n1=1, n2=1, order=1, l0=1.0, l1=1.0, l2=1.0, periodic0=0, period
     else:
       args+=[None]
     return __Brick_driver(args)
+
+Brick.__doc__=__Brick_driver.__doc__
diff --git a/finley/py_src/readers.py b/finley/py_src/readers.py
index 583c243..6531a88 100644
--- a/finley/py_src/readers.py
+++ b/finley/py_src/readers.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/src/Assemble.h b/finley/src/Assemble.h
index 5038407..4a1e4e8 100644
--- a/finley/src/Assemble.h
+++ b/finley/src/Assemble.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/Assemble_AverageElementData.cpp b/finley/src/Assemble_AverageElementData.cpp
index 30f52a2..0e84930 100644
--- a/finley/src/Assemble_AverageElementData.cpp
+++ b/finley/src/Assemble_AverageElementData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_CopyElementData.cpp b/finley/src/Assemble_CopyElementData.cpp
index d362d06..2f319ec 100644
--- a/finley/src/Assemble_CopyElementData.cpp
+++ b/finley/src/Assemble_CopyElementData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_CopyNodalData.cpp b/finley/src/Assemble_CopyNodalData.cpp
index 44a351c..4136628 100644
--- a/finley/src/Assemble_CopyNodalData.cpp
+++ b/finley/src/Assemble_CopyNodalData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_LumpedSystem.cpp b/finley/src/Assemble_LumpedSystem.cpp
index 1887f3e..cb02f6f 100644
--- a/finley/src/Assemble_LumpedSystem.cpp
+++ b/finley/src/Assemble_LumpedSystem.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_NodeCoordinates.cpp b/finley/src/Assemble_NodeCoordinates.cpp
index 36686de..115a260 100644
--- a/finley/src/Assemble_NodeCoordinates.cpp
+++ b/finley/src/Assemble_NodeCoordinates.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Util.h"
 #include "Assemble.h"
 
diff --git a/finley/src/Assemble_PDE.cpp b/finley/src/Assemble_PDE.cpp
index 8b9df2c..af9fb8d 100644
--- a/finley/src/Assemble_PDE.cpp
+++ b/finley/src/Assemble_PDE.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -45,6 +45,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 #include "esysUtils/blocktimer.h"
diff --git a/finley/src/Assemble_PDE_Points.cpp b/finley/src/Assemble_PDE_Points.cpp
index e000486..cb2ca2d 100644
--- a/finley/src/Assemble_PDE_Points.cpp
+++ b/finley/src/Assemble_PDE_Points.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -33,6 +33,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_PDE_Single_1D.cpp b/finley/src/Assemble_PDE_Single_1D.cpp
index 07dc854..1dc3b5d 100644
--- a/finley/src/Assemble_PDE_Single_1D.cpp
+++ b/finley/src/Assemble_PDE_Single_1D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_PDE_Single_2D.cpp b/finley/src/Assemble_PDE_Single_2D.cpp
index 9538361..10e00d9 100644
--- a/finley/src/Assemble_PDE_Single_2D.cpp
+++ b/finley/src/Assemble_PDE_Single_2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
@@ -63,6 +66,10 @@ void Assemble_PDE_Single_2D(const AssembleParameters& p,
 
 #pragma omp parallel
     {
+        std::vector<int> row_index(len_EM_F);
+        std::vector<double> EM_S(len_EM_S);
+        std::vector<double> EM_F(len_EM_F);
+
         for (int color=p.elements->minColor; color<=p.elements->maxColor; color++) {
             // loop over all elements:
 #pragma omp for
@@ -71,8 +78,8 @@ void Assemble_PDE_Single_2D(const AssembleParameters& p,
                     for (int isub=0; isub<p.numSub; isub++) {
                         const double *Vol=&(p.row_jac->volume[INDEX3(0,isub,e,p.numQuadSub,p.numSub)]);
                         const double *DSDX=&(p.row_jac->DSDX[INDEX5(0,0,0,isub,e, p.row_numShapesTotal,DIM,p.numQuadSub,p.numSub)]);
-                        std::vector<double> EM_S(len_EM_S);
-                        std::vector<double> EM_F(len_EM_F);
+                        std::fill(EM_S.begin(), EM_S.end(), 0);
+                        std::fill(EM_F.begin(), EM_F.end(), 0);
                         bool add_EM_F=false;
                         bool add_EM_S=false;
                         ///////////////
@@ -269,7 +276,6 @@ void Assemble_PDE_Single_2D(const AssembleParameters& p,
                         }
                         // add the element matrices onto the matrix and
                         // right hand side
-                        std::vector<int> row_index(p.row_numShapesTotal);
                         for (int q=0; q<p.row_numShapesTotal; q++)
                             row_index[q]=p.row_DOF[p.elements->Nodes[INDEX2(p.row_node[INDEX2(q,isub,p.row_numShapesTotal)],e,p.NN)]];
 
diff --git a/finley/src/Assemble_PDE_Single_3D.cpp b/finley/src/Assemble_PDE_Single_3D.cpp
index 160e365..7158d52 100644
--- a/finley/src/Assemble_PDE_Single_3D.cpp
+++ b/finley/src/Assemble_PDE_Single_3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -35,6 +35,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
@@ -63,6 +66,10 @@ void Assemble_PDE_Single_3D(const AssembleParameters& p,
 
 #pragma omp parallel
     {
+        std::vector<int> row_index(len_EM_F);
+        std::vector<double> EM_S(len_EM_S);
+        std::vector<double> EM_F(len_EM_F);
+
         for (int color=p.elements->minColor; color<=p.elements->maxColor; color++) {
             // loop over all elements:
 #pragma omp for
@@ -71,8 +78,8 @@ void Assemble_PDE_Single_3D(const AssembleParameters& p,
                     for (int isub=0; isub<p.numSub; isub++) {
                         const double *Vol=&(p.row_jac->volume[INDEX3(0,isub,e,p.numQuadSub,p.numSub)]);
                         const double *DSDX=&(p.row_jac->DSDX[INDEX5(0,0,0,isub,e,p.row_numShapesTotal,DIM,p.numQuadSub,p.numSub)]);
-                        std::vector<double> EM_S(len_EM_S);
-                        std::vector<double> EM_F(len_EM_F);
+                        std::fill(EM_S.begin(), EM_S.end(), 0);
+                        std::fill(EM_F.begin(), EM_F.end(), 0);
                         bool add_EM_F=false;
                         bool add_EM_S=false;
                         ///////////////
@@ -298,7 +305,6 @@ void Assemble_PDE_Single_3D(const AssembleParameters& p,
                         }
                         // add the element matrices onto the matrix and
                         // right hand side
-                        std::vector<int> row_index(p.row_numShapesTotal);
                         for (int q=0; q<p.row_numShapesTotal; q++)
                             row_index[q]=p.row_DOF[p.elements->Nodes[INDEX2(p.row_node[INDEX2(q,isub,p.row_numShapesTotal)],e,p.NN)]];
 
diff --git a/finley/src/Assemble_PDE_Single_C.cpp b/finley/src/Assemble_PDE_Single_C.cpp
index c42ba8e..96bc07a 100644
--- a/finley/src/Assemble_PDE_Single_C.cpp
+++ b/finley/src/Assemble_PDE_Single_C.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -31,6 +31,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
@@ -50,6 +53,7 @@ void Assemble_PDE_Single_C(const AssembleParameters& p, const escript::Data& D,
 
 #pragma omp parallel
     {
+        std::vector<int> row_index(p.row_numShapesTotal);
         std::vector<double> EM_S(p.row_numShapesTotal*p.col_numShapesTotal);
         std::vector<double> EM_F(p.row_numShapesTotal);
 
@@ -123,7 +127,6 @@ void Assemble_PDE_Single_C(const AssembleParameters& p, const escript::Data& D,
                         }
                         // add the element matrices onto the matrix and
                         // right hand side
-                        std::vector<int> row_index(p.row_numShapesTotal);
                         for (int q=0; q<p.row_numShapesTotal; q++)
                             row_index[q]=p.row_DOF[p.elements->Nodes[INDEX2(p.row_node[INDEX2(q,isub,p.row_numShapesTotal)],e,p.NN)]];
 
diff --git a/finley/src/Assemble_PDE_System_1D.cpp b/finley/src/Assemble_PDE_System_1D.cpp
index 918b729..243c64c 100644
--- a/finley/src/Assemble_PDE_System_1D.cpp
+++ b/finley/src/Assemble_PDE_System_1D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -38,6 +38,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_PDE_System_2D.cpp b/finley/src/Assemble_PDE_System_2D.cpp
index fe3e460..0e4bd5f 100644
--- a/finley/src/Assemble_PDE_System_2D.cpp
+++ b/finley/src/Assemble_PDE_System_2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -38,6 +38,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
@@ -66,6 +69,10 @@ void Assemble_PDE_System_2D(const AssembleParameters& p,
 
 #pragma omp parallel
     {
+        std::vector<int> row_index(p.row_numShapesTotal);
+        std::vector<double> EM_S(len_EM_S);
+        std::vector<double> EM_F(len_EM_F);
+
         for (int color=p.elements->minColor; color<=p.elements->maxColor; color++) {
             // loop over all elements:
 #pragma omp for
@@ -74,8 +81,8 @@ void Assemble_PDE_System_2D(const AssembleParameters& p,
                     for (int isub=0; isub<p.numSub; isub++) {
                         const double *Vol=&(p.row_jac->volume[INDEX3(0,isub,e,p.numQuadSub,p.numSub)]);
                         const double *DSDX=&(p.row_jac->DSDX[INDEX5(0,0,0,isub,e,p.row_numShapesTotal,DIM,p.numQuadSub,p.numSub)]);
-                        std::vector<double> EM_S(len_EM_S);
-                        std::vector<double> EM_F(len_EM_F);
+                        std::fill(EM_S.begin(), EM_S.end(), 0);
+                        std::fill(EM_F.begin(), EM_F.end(), 0);
                         bool add_EM_F=false;
                         bool add_EM_S=false;
                         //////////////////
@@ -318,7 +325,6 @@ void Assemble_PDE_System_2D(const AssembleParameters& p,
                         }
                         // add the element matrices onto the matrix and
                         // right hand side
-                        std::vector<int> row_index(p.row_numShapesTotal);
                         for (int q=0; q<p.row_numShapesTotal; q++)
                             row_index[q]=p.row_DOF[p.elements->Nodes[INDEX2(p.row_node[INDEX2(q,isub,p.row_numShapesTotal)],e,p.NN)]];
 
diff --git a/finley/src/Assemble_PDE_System_3D.cpp b/finley/src/Assemble_PDE_System_3D.cpp
index 0be1bb4..501f6d0 100644
--- a/finley/src/Assemble_PDE_System_3D.cpp
+++ b/finley/src/Assemble_PDE_System_3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -38,6 +38,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
@@ -66,6 +69,10 @@ void Assemble_PDE_System_3D(const AssembleParameters& p,
 
 #pragma omp parallel
     {
+        std::vector<int> row_index(p.row_numShapesTotal);
+        std::vector<double> EM_S(len_EM_S);
+        std::vector<double> EM_F(len_EM_F);
+
         for (int color=p.elements->minColor; color<=p.elements->maxColor; color++) {
             // loop over all elements:
 #pragma omp for
@@ -74,8 +81,8 @@ void Assemble_PDE_System_3D(const AssembleParameters& p,
                     for (int isub=0; isub<p.numSub; isub++) {
                         const double *Vol=&(p.row_jac->volume[INDEX3(0,isub,e,p.numQuadSub,p.numSub)]);
                         const double *DSDX=&(p.row_jac->DSDX[INDEX5(0,0,0,isub,e,p.row_numShapesTotal,DIM,p.numQuadSub,p.numSub)]);
-                        std::vector<double> EM_S(len_EM_S);
-                        std::vector<double> EM_F(len_EM_F);
+                        std::fill(EM_S.begin(), EM_S.end(), 0);
+                        std::fill(EM_F.begin(), EM_F.end(), 0);
                         bool add_EM_F=false;
                         bool add_EM_S=false;
                         ///////////////
@@ -353,7 +360,6 @@ void Assemble_PDE_System_3D(const AssembleParameters& p,
                         }
                         // add the element matrices onto the matrix and
                         // right hand side
-                        std::vector<int> row_index(p.row_numShapesTotal);
                         for (int q=0; q<p.row_numShapesTotal; q++)
                             row_index[q]=p.row_DOF[p.elements->Nodes[INDEX2(p.row_node[INDEX2(q,isub,p.row_numShapesTotal)],e,p.NN)]];
 
diff --git a/finley/src/Assemble_PDE_System_C.cpp b/finley/src/Assemble_PDE_System_C.cpp
index 2ffed91..f86af44 100644
--- a/finley/src/Assemble_PDE_System_C.cpp
+++ b/finley/src/Assemble_PDE_System_C.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -34,6 +34,10 @@
 
 /*  Author: Lutz Gross, l.gross at uq.edu.au */
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
@@ -53,6 +57,7 @@ void Assemble_PDE_System_C(const AssembleParameters& p, const escript::Data& D,
 
 #pragma omp parallel
     {
+        std::vector<int> row_index(p.row_numShapesTotal);
         std::vector<double> EM_S(p.row_numShapesTotal*p.col_numShapesTotal*p.numEqu*p.numComp);
         std::vector<double> EM_F(p.row_numShapesTotal*p.numEqu);
 
@@ -139,7 +144,6 @@ void Assemble_PDE_System_C(const AssembleParameters& p, const escript::Data& D,
                         }
                         // add the element matrices onto the matrix and
                         // right hand side
-                        std::vector<int> row_index(p.row_numShapesTotal);
                         for (int q=0; q<p.row_numShapesTotal; q++)
                             row_index[q]=p.row_DOF[p.elements->Nodes[INDEX2(p.row_node[INDEX2(q,isub,p.row_numShapesTotal)],e,p.NN)]];
                
diff --git a/finley/src/Assemble_addToSystemMatrix.cpp b/finley/src/Assemble_addToSystemMatrix.cpp
index e108ecf..ef17cf6 100644
--- a/finley/src/Assemble_addToSystemMatrix.cpp
+++ b/finley/src/Assemble_addToSystemMatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -30,6 +30,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 
 namespace finley {
diff --git a/finley/src/Assemble_getAssembleParameters.cpp b/finley/src/Assemble_getAssembleParameters.cpp
index 7dc5b76..ef420b4 100644
--- a/finley/src/Assemble_getAssembleParameters.cpp
+++ b/finley/src/Assemble_getAssembleParameters.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 
 namespace finley {
diff --git a/finley/src/Assemble_getNormal.cpp b/finley/src/Assemble_getNormal.cpp
index 1c4917b..a75f25c 100644
--- a/finley/src/Assemble_getNormal.cpp
+++ b/finley/src/Assemble_getNormal.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_getSize.cpp b/finley/src/Assemble_getSize.cpp
index 1a5a885..b4264df 100644
--- a/finley/src/Assemble_getSize.cpp
+++ b/finley/src/Assemble_getSize.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,8 @@
   of elements and assigns the value to each quadrature point in out.
 
 *****************************************************************************/
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 #include "Assemble.h"
 #include "Util.h"
diff --git a/finley/src/Assemble_gradient.cpp b/finley/src/Assemble_gradient.cpp
index 7c555e8..12af3e3 100644
--- a/finley/src/Assemble_gradient.cpp
+++ b/finley/src/Assemble_gradient.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_integrate.cpp b/finley/src/Assemble_integrate.cpp
index 50baf3c..6950c4d 100644
--- a/finley/src/Assemble_integrate.cpp
+++ b/finley/src/Assemble_integrate.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_interpolate.cpp b/finley/src/Assemble_interpolate.cpp
index 8db1a1d..96fd6fa 100644
--- a/finley/src/Assemble_interpolate.cpp
+++ b/finley/src/Assemble_interpolate.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -22,6 +22,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/Assemble_jacobians.cpp b/finley/src/Assemble_jacobians.cpp
index b463bb1..a1fa71d 100644
--- a/finley/src/Assemble_jacobians.cpp
+++ b/finley/src/Assemble_jacobians.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -33,6 +33,10 @@
     double* volume[numQuad*numElements]
 */
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Assemble.h"
 #include "Util.h"
 
diff --git a/finley/src/CPPAdapter/FinleyAdapterException.cpp b/finley/src/CPPAdapter/FinleyAdapterException.cpp
index b58e6ff..f6f6a30 100644
--- a/finley/src/CPPAdapter/FinleyAdapterException.cpp
+++ b/finley/src/CPPAdapter/FinleyAdapterException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/CPPAdapter/FinleyAdapterException.h b/finley/src/CPPAdapter/FinleyAdapterException.h
index 7aa251d..c2d75ce 100644
--- a/finley/src/CPPAdapter/FinleyAdapterException.h
+++ b/finley/src/CPPAdapter/FinleyAdapterException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/CPPAdapter/MeshAdapter.cpp b/finley/src/CPPAdapter/MeshAdapter.cpp
index b4c401e..46be4c8 100644
--- a/finley/src/CPPAdapter/MeshAdapter.cpp
+++ b/finley/src/CPPAdapter/MeshAdapter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <pasowrap/PasoException.h>
 #include <pasowrap/TransportProblemAdapter.h>
 #include "MeshAdapter.h"
@@ -2194,12 +2197,14 @@ void MeshAdapter::addDiracPoints(const vector<double>& points,
     Mesh* mesh=m_finleyMesh.get();
 
     if ( points.size() % dim != 0 ) {
-        throw FinleyAdapterException("Error - number of coords does not appear to be a multiple of dimension.");
+        char err[200];
+        sprintf(err,"Error - number of coords in diractags is %ld this should be a multiple of the specified dimension:%d.",points.size(),dim);
+        throw FinleyAdapterException(err);
     }
 
     if (numPoints != numTags)
     {
-	throw FinleyAdapterException("Error - number of diractags must match number of diracpoints.");
+	   throw FinleyAdapterException("Error - number of diractags must match number of diracpoints.");
     }
 
     if (numPoints > 0) {
diff --git a/finley/src/CPPAdapter/MeshAdapter.h b/finley/src/CPPAdapter/MeshAdapter.h
index c61deec..fc99178 100644
--- a/finley/src/CPPAdapter/MeshAdapter.h
+++ b/finley/src/CPPAdapter/MeshAdapter.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -443,10 +443,8 @@ public:
      \brief
      return the identifier of the matrix type to be used for the global stiffness matrix when a particular solver, package, perconditioner,
      and symmetric matrix is used.
-     \param solver 
-     \param preconditioner
-     \param package
-     \param symmetry 
+     \param options a python object containing the solver, package,
+            preconditioner and symmetry
   */
   virtual int getSystemMatrixTypeId(const boost::python::object& options) const;
 
diff --git a/finley/src/CPPAdapter/MeshAdapterFactory.cpp b/finley/src/CPPAdapter/MeshAdapterFactory.cpp
index 38a38cc..1867ed0 100644
--- a/finley/src/CPPAdapter/MeshAdapterFactory.cpp
+++ b/finley/src/CPPAdapter/MeshAdapterFactory.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "MeshAdapterFactory.h"
 #include "esysUtils/blocktimer.h"
 #ifdef ESYS_MPI
@@ -562,7 +565,8 @@ namespace finley {
               points.push_back(extract<double>(temp[k]));
           }
       }
-      int curmax=40; // bricks use up to 30
+      int curmax=40; // bricks use up to 200 but the existing tag check 
+		     // will find that
       TagMap& tagmap=dynamic_cast<MeshAdapter*>(result.get())->getMesh()->tagMap;
 		// first we work out what tags are already in use
       for (TagMap::iterator it=tagmap.begin();
diff --git a/finley/src/CPPAdapter/MeshAdapterFactory.h b/finley/src/CPPAdapter/MeshAdapterFactory.h
index 282f6f5..4a4e9ce 100644
--- a/finley/src/CPPAdapter/MeshAdapterFactory.h
+++ b/finley/src/CPPAdapter/MeshAdapterFactory.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/CPPAdapter/finleycpp.cpp b/finley/src/CPPAdapter/finleycpp.cpp
index db7fa09..9374042 100644
--- a/finley/src/CPPAdapter/finleycpp.cpp
+++ b/finley/src/CPPAdapter/finleycpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #ifdef ESYS_MPI
 #include "esysUtils/Esys_MPI.h"
@@ -43,23 +46,6 @@
 
 using namespace boost::python;
 
-//
-// The BOOST_PYTHON_FUNCTION_OVERLOADS macro generates function overloads for optional
-// arguments to the respective finley functions.
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-//
-// NOTE: If the number of arguments to the finley functions change
-// the magic numbers in the BOOST_PYTHON_FUNCTION_OVERLOADS call 
-// must change.
-//
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// BOOST_PYTHON_FUNCTION_OVERLOADS(readMesh_overloads,finley::readMesh,1,2)
-// BOOST_PYTHON_FUNCTION_OVERLOADS(brick_overloads,finley::brick,0,12)
-// BOOST_PYTHON_FUNCTION_OVERLOADS(rectangle_overloads,finley::rectangle,0,9)
-// BOOST_PYTHON_FUNCTION_OVERLOADS(interval_overloads,finley::interval,0,6)
-// BOOST_PYTHON_FUNCTION_OVERLOADS(glueFaces_overloads,finley::glueFaces,1,3)
-// BOOST_PYTHON_FUNCTION_OVERLOADS(joinFaces_overloads,finley::joinFaces,1,3)
-
 BOOST_PYTHON_MODULE(finleycpp)
 {
 // This feature was added in boost v1.34
@@ -130,7 +116,6 @@ BOOST_PYTHON_MODULE(finleycpp)
 
   def ("__Rectangle_driver",finley::rectangle_driver,
       (arg("args")) 
-//       ,return_value_policy<manage_new_object>());
 ,"Creates a rectangular mesh with n0 x n1 elements over the brick [0,l0] x [0,l1]."
 "\n\n:param n0:\n:type n0:\n:param n1:\n:type n1:\n"
 ":param order: =1, =-1 or =2 gives the order of shape function. If -1 macro elements of order 1 are used.\n"
@@ -146,7 +131,6 @@ BOOST_PYTHON_MODULE(finleycpp)
 );
 
   def("Merge",finley::meshMerge,args("meshList")
-//       ,return_value_policy<manage_new_object>());
 ,"Merges a list of meshes into one mesh.\n\n:rtype: `Domain`"
   );
 
@@ -154,7 +138,6 @@ BOOST_PYTHON_MODULE(finleycpp)
       (arg("meshList"),arg("safetyFactor")=0.2,
       arg("tolerance")=1.e-8,
       arg("optimize")=true)
-//       ,return_value_policy<manage_new_object>());
 ,"Detects matching faces in the mesh, removes them from the mesh and joins the elements touched by the face elements."
 	);
 
@@ -162,7 +145,6 @@ BOOST_PYTHON_MODULE(finleycpp)
       (arg("meshList"), arg("safetyFactor")=0.2,
       arg("tolerance")=1.e-8,
       arg("optimize")=true)
-//       ,return_value_policy<manage_new_object>());
 ,"Detects matching faces in the mesh and replaces them by joint elements."
 	);
 
diff --git a/finley/src/CPPAdapter/system_dep.h b/finley/src/CPPAdapter/system_dep.h
index d89cf3a..36798eb 100644
--- a/finley/src/CPPAdapter/system_dep.h
+++ b/finley/src/CPPAdapter/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,20 +26,7 @@
 #ifndef finley_system_dep_h
 #define finley_system_dep_h
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/*
- * The Intel compiler on windows has an "improved" math library compared to
- * the usual Visual C++ one. In particular it has acosh and other similar
- * functions which aren't implemented in Visual C++ math.h.
- * Note you will get a compile time error if any other header (including
- * system ones) includes math.h whilst mathimf.h has been included.
- * As a result system_dep.h must be included FIRST at all times (this
- * prevents math.h from being included).
- */
-#   include <mathimf.h>
-#else
-#   include <cmath>
-#endif
+#include <cmath>
 
 #define FINLEY_DLL_API
 
diff --git a/finley/src/ElementFile.cpp b/finley/src/ElementFile.cpp
index 1af064c..ccc2db0 100644
--- a/finley/src/ElementFile.cpp
+++ b/finley/src/ElementFile.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "ElementFile.h"
 #include <escript/Data.h>
 
diff --git a/finley/src/ElementFile.h b/finley/src/ElementFile.h
index dfc58b7..b8c9f43 100644
--- a/finley/src/ElementFile.h
+++ b/finley/src/ElementFile.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/ElementFile_jacobians.cpp b/finley/src/ElementFile_jacobians.cpp
index f107fa9..bde92a7 100644
--- a/finley/src/ElementFile_jacobians.cpp
+++ b/finley/src/ElementFile_jacobians.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "ElementFile.h"
 #include "Assemble.h"
 
diff --git a/finley/src/Finley.cpp b/finley/src/Finley.cpp
index 5251cd2..f729bae 100644
--- a/finley/src/Finley.cpp
+++ b/finley/src/Finley.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/Finley.h b/finley/src/Finley.h
index 1e6a947..d5029bc 100644
--- a/finley/src/Finley.h
+++ b/finley/src/Finley.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/FinleyVersion.h b/finley/src/FinleyVersion.h
index 4145797..5250095 100644
--- a/finley/src/FinleyVersion.h
+++ b/finley/src/FinleyVersion.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -18,6 +18,6 @@
 #ifndef INC_FINLEYVERSION
 #define INC_FINLEYVERSION
 
-char Finley_Version[]="$Revision: 4657 $";
+char Finley_Version[]="$Revision: 5593 $";
 
 #endif 
diff --git a/finley/src/IndexList.cpp b/finley/src/IndexList.cpp
index a6fa7b6..baa4736 100644
--- a/finley/src/IndexList.cpp
+++ b/finley/src/IndexList.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "IndexList.h"
 #include "ElementFile.h"
 
diff --git a/finley/src/IndexList.h b/finley/src/IndexList.h
index b02674f..3f84429 100644
--- a/finley/src/IndexList.h
+++ b/finley/src/IndexList.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/Mesh.cpp b/finley/src/Mesh.cpp
index 8068a16..885f5ed 100644
--- a/finley/src/Mesh.cpp
+++ b/finley/src/Mesh.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -20,6 +20,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Mesh.h"
 #include "IndexList.h"
 #include <boost/scoped_array.hpp>
diff --git a/finley/src/Mesh.h b/finley/src/Mesh.h
index 90e0238..135ee4a 100644
--- a/finley/src/Mesh.h
+++ b/finley/src/Mesh.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -131,6 +131,12 @@ private:
     void optimizeElementOrdering();
     void setOrders();
     void updateTagList();
+    static Mesh* readGmshSlave(esysUtils::JMPI& mpi_info, const std::string fname, int numDim, int order,
+                          int reducedOrder, bool optimize,
+                          bool useMacroElements);
+    static Mesh* readGmshMaster(esysUtils::JMPI& mpi_info, const std::string fname, int numDim, int order,
+                          int reducedOrder, bool optimize,
+                          bool useMacroElements);
 
 public:
     // the name of the mesh
diff --git a/finley/src/Mesh_addPoints.cpp b/finley/src/Mesh_addPoints.cpp
index fa17079..04a3a0b 100644
--- a/finley/src/Mesh_addPoints.cpp
+++ b/finley/src/Mesh_addPoints.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Mesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_findMatchingFaces.cpp b/finley/src/Mesh_findMatchingFaces.cpp
index d5648bc..670724c 100644
--- a/finley/src/Mesh_findMatchingFaces.cpp
+++ b/finley/src/Mesh_findMatchingFaces.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Util.h"
 #include "Mesh.h"
 
diff --git a/finley/src/Mesh_getPattern.cpp b/finley/src/Mesh_getPattern.cpp
index a0d1423..1eb905d 100644
--- a/finley/src/Mesh_getPattern.cpp
+++ b/finley/src/Mesh_getPattern.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Mesh.h"
 #include "IndexList.h"
 #include <boost/scoped_array.hpp>
diff --git a/finley/src/Mesh_glueFaces.cpp b/finley/src/Mesh_glueFaces.cpp
index 2050719..fa34164 100644
--- a/finley/src/Mesh_glueFaces.cpp
+++ b/finley/src/Mesh_glueFaces.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_hex20.cpp b/finley/src/Mesh_hex20.cpp
index 8bb897b..3ec58cd 100644
--- a/finley/src/Mesh_hex20.cpp
+++ b/finley/src/Mesh_hex20.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,6 +26,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "RectangularMesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_hex8.cpp b/finley/src/Mesh_hex8.cpp
index f97477e..bb0e9ed 100644
--- a/finley/src/Mesh_hex8.cpp
+++ b/finley/src/Mesh_hex8.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,6 +26,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "RectangularMesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_joinFaces.cpp b/finley/src/Mesh_joinFaces.cpp
index 9b968e4..4bbf319 100644
--- a/finley/src/Mesh_joinFaces.cpp
+++ b/finley/src/Mesh_joinFaces.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,6 +23,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Mesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_merge.cpp b/finley/src/Mesh_merge.cpp
index 0e2923a..9fbcc46 100644
--- a/finley/src/Mesh_merge.cpp
+++ b/finley/src/Mesh_merge.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,6 +24,10 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Mesh.h"
 #include "Util.h"
 
diff --git a/finley/src/Mesh_optimizeDOFDistribution.cpp b/finley/src/Mesh_optimizeDOFDistribution.cpp
index 729c0ae..06d25bc 100644
--- a/finley/src/Mesh_optimizeDOFDistribution.cpp
+++ b/finley/src/Mesh_optimizeDOFDistribution.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -23,10 +23,17 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "Mesh.h"
 #include "IndexList.h"
 #ifdef USE_PARMETIS
 #include <parmetis.h>
+#ifndef REALTYPEWIDTH
+typedef float real_t;
+#endif
 #endif
 #include <boost/scoped_array.hpp>
 
@@ -106,13 +113,13 @@ void Mesh::optimizeDOFDistribution(std::vector<int>& distribution)
         paso::Pattern_ptr pattern(paso::Pattern::fromIndexListArray(0,
                 myNumVertices, index_list.get(), 0, globalNumVertices, 0));
         // set the coordinates
-        std::vector<float> xyz(myNumVertices*dim);
+        std::vector<real_t> xyz(myNumVertices*dim);
 #pragma omp parallel for
         for (int i=0; i<Nodes->numNodes; ++i) {
             const int k=Nodes->globalDegreesOfFreedom[i]-myFirstVertex;
             if (k>=0 && k<myNumVertices) {
                 for (int j=0; j<dim; ++j)
-                    xyz[k*dim+j]=static_cast<float>(Nodes->Coordinates[INDEX2(j,i,dim)]); 
+                    xyz[k*dim+j]=static_cast<real_t>(Nodes->Coordinates[INDEX2(j,i,dim)]); 
             }
         }
 
@@ -120,9 +127,12 @@ void Mesh::optimizeDOFDistribution(std::vector<int>& distribution)
         int numflag = 0;
         int ncon = 1;
         int edgecut;
-        int options[2] = { 3, 15 };
-        std::vector<float> tpwgts(ncon*mpiSize, 1.f/mpiSize);
-        std::vector<float> ubvec(ncon, 1.05f);
+        // options[0]=1 -> non-default values, evaluate rest of options
+        // options[1]=15 -> DBG_TIME | DBG_INFO | DBG_PROGRESS | DBG_REFINEINFO
+        // options[2] -> random seed
+        int options[3] = { 1, 15, 0 };
+        std::vector<real_t> tpwgts(ncon*mpiSize, 1.f/mpiSize);
+        std::vector<real_t> ubvec(ncon, 1.05f);
         ParMETIS_V3_PartGeomKway(&distribution[0], pattern->ptr, pattern->index,
                               NULL, NULL, &wgtflag, &numflag, &dim, &xyz[0],
                               &ncon, &mpiSize, &tpwgts[0], &ubvec[0], options,
diff --git a/finley/src/Mesh_read.cpp b/finley/src/Mesh_read.cpp
index 6180900..1c5717c 100644
--- a/finley/src/Mesh_read.cpp
+++ b/finley/src/Mesh_read.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ctype.h>
 #include "Mesh.h"
 
diff --git a/finley/src/Mesh_readGmsh.cpp b/finley/src/Mesh_readGmsh.cpp
index 5eb829f..9f0606d 100644
--- a/finley/src/Mesh_readGmsh.cpp
+++ b/finley/src/Mesh_readGmsh.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,16 +21,22 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 #include <cstdio>
 #include "CPPAdapter/FinleyAdapterException.h"
 
 //can't return because the flag need to be shared across all nodes
-#define FSCANF_CHECK(scan_ret) { if (scan_ret == EOF) { errorFlag = 1;} }
+#define SSCANF_CHECK(scan_ret) { if (scan_ret == EOF) { errorFlag = 1;} }
 #define MAX_numNodes_gmsh 20
 
 #define EARLY_EOF 1
+#define MISSING_NODES 2
+#define MISSING_ELEMENTS 3
 #define THROW_ERROR 4
+#define SUCCESS 5
 #define ERROR 6
 /*
     error flags include:
@@ -55,31 +61,65 @@ struct ElementInfo {
 bool is_node_string(char *line) {
     if (line == NULL)
         return false;
-    return !strncmp(line, "$NOD", 4) || !strncmp(line, "$NOE", 4) 
+    return !strncmp(line, "$NOD", 4) || !strncmp(line, "$NOE", 4)
             || !strncmp(line, "$Nodes", 6);
 }
 
 bool is_endnode_string(char *line) {
     if (line == NULL)
         return false;
-    return !strncmp(line, "$ENDNOD", 7) || !strncmp(line, "$ENDNOE", 7) 
+    return !strncmp(line, "$ENDNOD", 7) || !strncmp(line, "$ENDNOE", 7)
             || !strncmp(line, "$EndNodes", 9);
 }
 
+bool get_line(std::vector<char>& line, FILE *file) {
+    int capacity = 1024;
+    line.clear();
+    line.resize(capacity);
+    char *tmp = &line[0];
+    char *res = NULL;
+    //not terribly efficient, but any line longer than 1024 
+    //is probably already bad
+    while ((res = fgets(tmp, 1023, file)) == tmp
+            && strchr(tmp, '\n') == NULL) {
+        capacity += 1024;
+        line.resize(capacity);
+        tmp = strchr(&line[0], '\0'); //this bit is awful, O(n) instead of O(1)
+        if (capacity > LenString_MAX) {//madness
+            res = NULL;
+            break;
+        }
+    }
+    return res == tmp; //true if line read, false if EOF without or without \n
+}
+
 namespace finley {
 
+char *next_space(char **position, int count) {
+    for (int i = 0; i < count; i++) {
+        *position = strchr(*position, ' ');
+        if ((*position)++ == NULL)//move off the space
+            return NULL;
+    }
+    return *position;
+}
+
 int getSingleElement(FILE *f, int dim, double version, struct ElementInfo& e,
         char *error_msg, const char *fname, bool useMacroElements)
 {
     int gmsh_type = -1;
-    int numTags=0;
-    int scan_ret = fscanf(f, "%d %d", &e.id, &gmsh_type);
-    if (scan_ret == EOF)
+
+    std::vector<char> line;
+    if (!get_line(line, f))
         return EARLY_EOF;
-    else if (scan_ret != 2) {
+    char *position = &line[0];
+    if (sscanf(position, "%d %d", &e.id, &gmsh_type) != 2) {
         sprintf(error_msg, "malformed mesh file");
         return THROW_ERROR;
     }
+    if (next_space(&position, 2) == NULL)
+        return EARLY_EOF;
+
     int numNodesPerElement = 0;
     switch (gmsh_type) {
         case 1:  /* line order 1 */
@@ -166,53 +206,45 @@ int getSingleElement(FILE *f, int dim, double version, struct ElementInfo& e,
     }
     if (version <= 1.0){
         int tmp = 0;
-        scan_ret = fscanf(f, "%d %*d %d", &e.tag, &tmp);
-        if (scan_ret == EOF)
+        if (sscanf(position, "%d %*d %d", &e.tag, &tmp) == 0
+                || next_space(&position, 3) == NULL )
             return EARLY_EOF;
         if (tmp != numNodesPerElement) {
             sprintf(error_msg,"Illegal number of nodes for element %d in mesh file %s.", e.id, fname);
             return THROW_ERROR;
         }
     } else {
-        scan_ret = fscanf(f, "%d", &numTags);
-        if (scan_ret == EOF)
-            return EARLY_EOF;
         e.tag = 1;
-        for (int j = 0; j < numTags; j++){
-            int tmp = 0;
-            scan_ret = fscanf(f, "%d", &tmp);
-            if (scan_ret == EOF)
-                return EARLY_EOF;
-            if (j == 0) {
-              e.tag = tmp;
-            }
-            /* ignore any other tags, second tag would be elementary id,
-             third tag would be partition id */
-        }
+        int numTags=0; //this is garbage and never used
+        if (sscanf(position, "%d", &numTags) == 0 
+                || next_space(&position, 1) == NULL)
+            return EARLY_EOF;
+        if (sscanf(position, "%d", &e.tag) == 0 
+                || next_space(&position, numTags) == NULL)
+            return EARLY_EOF;
+        /* ignore any other tags, second tag would be elementary id,
+         third tag would be partition id */
     }
 
     if (!noError()) {
         return ERROR;
     }
     for(int j = 0; j < numNodesPerElement; j++) {
-        scan_ret = fscanf(f, "%d", e.vertex+j);
-        if (scan_ret == EOF)
+        if (sscanf(position, "%d", e.vertex+j) == 0 
+                || next_space(&position, 1) == NULL)
             return EARLY_EOF;
     }
     return 0;
 }
 
-
-
-int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p, 
+int getElementsMaster(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
         char * error_msg, bool useMacroElements, const std::string fname,
         int numDim, double version, int order, int reduced_order) {
-    /*  
-     *  This function should read in the elements and distribute 
+    /*
+     *  This function should read in the elements and distribute
      *  them to the apropriate process.
      */
     int errorFlag=0;
-
     ElementTypeId final_element_type = NoRef;
     ElementTypeId final_face_element_type = NoRef;
     ElementTypeId contact_element_type = NoRef;
@@ -221,25 +253,20 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
     const_ReferenceElementSet_ptr refFaceElements, refElements;
     int *id, *tag;
     ElementTypeId * element_type;
-    if (mpi_info->rank == 0) {
-        int scan_ret = fscanf(fileHandle_p, "%d", &totalNumElements);
-        FSCANF_CHECK(scan_ret);
-    }
-    
+    std::vector<char> line;
+    if (!get_line(line, fileHandle_p))
+        errorFlag = EARLY_EOF;
+    int scan_ret = sscanf(&line[0], "%d", &totalNumElements);
+    SSCANF_CHECK(scan_ret);
+
 #ifdef ESYS_MPI
     // Broadcast numNodes if there are multiple mpi procs
     if (mpi_info->size > 1) {
-        int msg[1];
-        if (mpi_info->rank == 0) {
-            msg[0] = totalNumElements;
-        } else {
-            msg[0] = 0;
-        }
-        MPI_Bcast(msg, 1, MPI_INT, 0, mpi_info->comm);
-        totalNumElements = msg[0];
+        int msg = totalNumElements;
+        MPI_Bcast(&msg, 1, MPI_INT, 0, mpi_info->comm);
     }
 #endif
-    
+
     int chunkSize = totalNumElements / mpi_info->size + 1, chunkElements=0;
     int chunkFaceElements=0, chunkOtherElements=0;
     id = new int[chunkSize+1];
@@ -248,10 +275,10 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
     element_type = new ElementTypeId[chunkSize+1];
     std::vector<int> elementIndices (chunkSize, -1);
     std::vector<int> faceElementIndices (chunkSize, -1);
-    
 
 
-#ifdef ESYS_MPI        
+
+#ifdef ESYS_MPI
     int chunkInfo[2];//chunkInfo stores the number of element and number of face elements
     int cpuId = 0;
 #endif
@@ -263,123 +290,88 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
         tag[i] = -1;
         element_type[i] = NoRef;
     }
-    
-    if (mpi_info->rank == 0) {
-      /* read all in */
-        for(int e = 0, count = 0; e < totalNumElements; e++, count++) {
-            struct ElementInfo element = {NoRef, 0, 0, &vertices[count*MAX_numNodes_gmsh], 0};
-            getSingleElement(fileHandle_p, numDim, version,
-                    element, error_msg, fname.c_str(), useMacroElements);
-            element_type[count] = element.type;
-            id[count] = element.id;
-            tag[count] = element.tag;
-            
-            /* for tet10 the last two nodes need to be swapped */
-            if ((element.type==Tet10) || (element.type == Tet10Macro)) {
-                int vertex = vertices[INDEX2(9,count,MAX_numNodes_gmsh)];
-                vertices[INDEX2(9,count,MAX_numNodes_gmsh)] = vertices[INDEX2(8,count,MAX_numNodes_gmsh)];
-                vertices[INDEX2(8,count,MAX_numNodes_gmsh)] = vertex;
+
+    /* read all in */
+    for(int e = 0, count = 0; e < totalNumElements; e++, count++) {
+        struct ElementInfo element = {NoRef, 0, 0, &vertices[count*MAX_numNodes_gmsh], 0};
+        getSingleElement(fileHandle_p, numDim, version,
+                element, error_msg, fname.c_str(), useMacroElements);
+        element_type[count] = element.type;
+        id[count] = element.id;
+        tag[count] = element.tag;
+
+        /* for tet10 the last two nodes need to be swapped */
+        if ((element.type==Tet10) || (element.type == Tet10Macro)) {
+            int vertex = vertices[INDEX2(9,count,MAX_numNodes_gmsh)];
+            vertices[INDEX2(9,count,MAX_numNodes_gmsh)] = vertices[INDEX2(8,count,MAX_numNodes_gmsh)];
+            vertices[INDEX2(8,count,MAX_numNodes_gmsh)] = vertex;
+        }
+
+        if (element.dim == numDim) {
+            if (final_element_type == NoRef) {
+               final_element_type = element.type;
+            } else if (final_element_type != element.type) {
+                sprintf(error_msg,"Finley can only handle a single type of internal elements.");
+                errorFlag = THROW_ERROR;
             }
-            
-            if (element.dim == numDim) {
-               if (final_element_type == NoRef) {
-                  final_element_type = element.type;
-               } else if (final_element_type != element.type) {
-                   sprintf(error_msg,"Finley can handle a single type of internal elements only.");
-                   errorFlag = THROW_ERROR;
-               }
-               elementIndices[chunkElements]=count;
-               numElements++;
-               chunkElements++;
-            } else if (element.dim == numDim-1) {
-               if (final_face_element_type == NoRef) {
-                  final_face_element_type = element.type;
-               } else if (final_face_element_type != element.type) {
-                   sprintf(error_msg,"Finley can handle a single type of face elements only.");
-                   errorFlag = THROW_ERROR;
-               }
-               faceElementIndices[chunkFaceElements]=count;
-               numFaceElements++;
-               chunkFaceElements++;
-            } else{
-                chunkOtherElements++;
+            elementIndices[chunkElements]=count;
+            numElements++;
+            chunkElements++;
+        } else if (element.dim == numDim-1) {
+            if (final_face_element_type == NoRef) {
+               final_face_element_type = element.type;
+            } else if (final_face_element_type != element.type) {
+               sprintf(error_msg,"Finley can only handle a single type of face elements.");
+               errorFlag = THROW_ERROR;
             }
+            faceElementIndices[chunkFaceElements]=count;
+            numFaceElements++;
+            chunkFaceElements++;
+        } else {
+            chunkOtherElements++;
+        }
 #ifdef ESYS_MPI
-            if(count < chunkSize - 1)
-                continue;
-            cpuId++;
-            chunkInfo[0]=chunkElements;
-            chunkInfo[1]=chunkFaceElements;
-
-            if(cpuId >= mpi_info->size) {
-                continue;
-            }
-            if(!errorFlag){         
+        if(count < chunkSize - 1)
+            continue;
+        chunkInfo[0]=chunkElements;
+        chunkInfo[1]=chunkFaceElements;
+
+        if(cpuId++ > mpi_info->size) {
+            continue;
+        }
+        if(errorFlag){
+            for(; cpuId<mpi_info->size; cpuId++) {
                 MPI_Send(&errorFlag, 1, MPI_INT, cpuId, 81719, mpi_info->comm);
-                MPI_Send(&vertices[0], chunkSize*MAX_numNodes_gmsh, MPI_INT, cpuId, 81720, mpi_info->comm);
-                MPI_Send(id, chunkSize, MPI_INT, cpuId, 81721, mpi_info->comm);
-                MPI_Send(tag, chunkSize, MPI_INT, cpuId, 81722, mpi_info->comm);
-                MPI_Send(element_type, chunkSize, MPI_INT, cpuId, 81723, mpi_info->comm);
-                MPI_Send(chunkInfo, 2, MPI_INT, cpuId, 81724, mpi_info->comm);
-                MPI_Send(&(elementIndices[0]), chunkElements, MPI_INT, cpuId, 81725, mpi_info->comm);
-                MPI_Send(&(faceElementIndices[0]), chunkFaceElements, MPI_INT, cpuId, 81726, mpi_info->comm);
-            } else{
-                //let the remaining processes know something has gone wrong
-                for(; cpuId<mpi_info->size; cpuId++) {
-                    MPI_Send(&errorFlag, 1, MPI_INT, cpuId, 81719, mpi_info->comm);
-                }                    
-                break;
             }
-            
-            // reset arrays for next cpu
+            break;
+        }
+        MPI_Send(&errorFlag, 1, MPI_INT, cpuId, 81719, mpi_info->comm);
+        MPI_Send(&vertices[0], chunkSize*MAX_numNodes_gmsh, MPI_INT, cpuId, 81720, mpi_info->comm);
+        MPI_Send(id, chunkSize, MPI_INT, cpuId, 81721, mpi_info->comm);
+        MPI_Send(tag, chunkSize, MPI_INT, cpuId, 81722, mpi_info->comm);
+        MPI_Send(element_type, chunkSize, MPI_INT, cpuId, 81723, mpi_info->comm);
+        MPI_Send(chunkInfo, 2, MPI_INT, cpuId, 81724, mpi_info->comm);
+        MPI_Send(&(elementIndices[0]), chunkElements, MPI_INT, cpuId, 81725, mpi_info->comm);
+        MPI_Send(&(faceElementIndices[0]), chunkFaceElements, MPI_INT, cpuId, 81726, mpi_info->comm);
+
+        // reset arrays for next cpu
 #pragma omp parallel for schedule(static)
-            for (int i=0; i<chunkSize*MAX_numNodes_gmsh; i++)
-                vertices[i] = -1;
+        for (int i=0; i<chunkSize*MAX_numNodes_gmsh; i++)
+            vertices[i] = -1;
 #pragma omp parallel for schedule(static)
-            for (int i=0; i<chunkSize; i++) {
-                id[i] = -1;
-                tag[i] = -1;
-                element_type[i] = NoRef;
-            }
-            chunkElements=0;
-            chunkFaceElements=0;
-            chunkOtherElements=0;
-            count = -1;
-#endif
-
-            //end elment reading for loop
-            if (errorFlag)
-            {
-                break;
-            }
-        }
-    } else {
-#ifdef ESYS_MPI
-        /* Each worker receives messages */
-        if(mpi_info->size>1){
-            MPI_Status status;
-
-            MPI_Recv(&errorFlag, 1, MPI_INT,0, 81719, mpi_info->comm, &status);
-            if(!errorFlag){
-                MPI_Recv(&vertices[0], chunkSize*MAX_numNodes_gmsh, MPI_INT, 0, 81720, mpi_info->comm, &status);
-                MPI_Recv(id, chunkSize, MPI_INT, 0, 81721, mpi_info->comm, &status);
-                MPI_Recv(tag, chunkSize, MPI_INT, 0, 81722, mpi_info->comm, &status);
-                MPI_Recv(element_type, chunkSize, MPI_INT, 0, 81723, mpi_info->comm, &status);
-                MPI_Recv(chunkInfo, 2, MPI_INT, 0, 81724, mpi_info->comm, &status);
-                chunkElements = chunkInfo[0];
-                chunkFaceElements = chunkInfo[1];
-                MPI_Recv(&(elementIndices[0]), chunkElements, MPI_INT, 0, 81725, mpi_info->comm,&status);
-                MPI_Recv(&(faceElementIndices[0]), chunkFaceElements, MPI_INT, 0, 81726, mpi_info->comm,&status);
-            } else {
-                return errorFlag;
-            }
+        for (int i=0; i<chunkSize; i++) {
+            id[i] = -1;
+            tag[i] = -1;
+            element_type[i] = NoRef;
         }
+        chunkElements=0;
+        chunkFaceElements=0;
+        chunkOtherElements=0;
+        count = -1;
 #endif
-
     }
 
-
-#ifdef ESYS_MPI    
+#ifdef ESYS_MPI
     if(mpi_info->size>1){
         MPI_Bcast(&errorFlag, 1, MPI_INT,  0, mpi_info->comm);
     }
@@ -387,67 +379,201 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
     if(errorFlag){
         return errorFlag;
     }
-    
+
     // all elements have been read and shared, now we have to identify the
     // elements for finley
     if (!noError()) {
         return ERROR;
     }
-    if (mpi_info->rank == 0) {
-        /* first we have to identify the elements to define Elements and FaceElements */
-        if (final_element_type == NoRef) {
-            if (numDim==1) {
-               final_element_type=Line2;
-            } else if (numDim==2) {
-               final_element_type=Tri3;
-            } else if (numDim==3) {
-               final_element_type=Tet4;
-            }
+    /* first we have to identify the elements to define Elements and FaceElements */
+    if (final_element_type == NoRef) {
+        if (numDim==1) {
+           final_element_type=Line2;
+        } else if (numDim==2) {
+           final_element_type=Tri3;
+        } else if (numDim==3) {
+           final_element_type=Tet4;
         }
-        if (final_face_element_type == NoRef) {
-            if (numDim==1) {
-               final_face_element_type=Point1;
-            } else if (numDim==2) {
-               final_face_element_type=Line2;
-            } else if (numDim==3) {
-               final_face_element_type=Tri3;
-            }
-        }
-        if (final_face_element_type == Line2) {
-            contact_element_type=Line2_Contact;
-        } else  if ( (final_face_element_type == Line3) || (final_face_element_type == Line3Macro) ) {
-            contact_element_type=Line3_Contact;
-        } else  if (final_face_element_type == Tri3) {
-            contact_element_type=Tri3_Contact;
-        } else  if ( (final_face_element_type == Tri6) || (final_face_element_type == Tri6Macro)) {
-            contact_element_type=Tri6_Contact;
-        } else {
-            contact_element_type=Point1_Contact;
+    }
+    if (final_face_element_type == NoRef) {
+        if (numDim==1) {
+           final_face_element_type=Point1;
+        } else if (numDim==2) {
+           final_face_element_type=Line2;
+        } else if (numDim==3) {
+           final_face_element_type=Tri3;
         }
-    } 
-    
+    }
+    if (final_face_element_type == Line2) {
+        contact_element_type=Line2_Contact;
+    } else  if ( (final_face_element_type == Line3) || (final_face_element_type == Line3Macro) ) {
+        contact_element_type=Line3_Contact;
+    } else  if (final_face_element_type == Tri3) {
+        contact_element_type=Tri3_Contact;
+    } else  if ( (final_face_element_type == Tri6) || (final_face_element_type == Tri6Macro)) {
+        contact_element_type=Tri6_Contact;
+    } else {
+        contact_element_type=Point1_Contact;
+    }
+
 #ifdef ESYS_MPI
-        // Broadcast numNodes if there are multiple mpi procs
-        if (mpi_info->size > 1) {
-            int msg[3];
-            if (mpi_info->rank == 0) {
-                msg[0] = final_element_type;
-                msg[1] = final_face_element_type;
-                msg[2] = contact_element_type;
-            } else {
-                msg[0] = 0;
-                msg[1] = 0;
-                msg[2] = 0;
-            }
-            MPI_Bcast(msg, 3, MPI_INT,  0, mpi_info->comm);
-            final_element_type = static_cast<ElementTypeId>(msg[0]);
-            final_face_element_type = static_cast<ElementTypeId>(msg[1]);
-            contact_element_type = static_cast<ElementTypeId>(msg[2]);
-        }
+    // Broadcast numNodes if there are multiple mpi procs
+    if (mpi_info->size > 1) {
+        int msg[3] = {final_element_type, final_face_element_type, 
+                contact_element_type};
+        MPI_Bcast(msg, 3, MPI_INT,  0, mpi_info->comm);
+    }
 #endif
 
 
-        
+
+    refElements.reset(new ReferenceElementSet(final_element_type, order, reduced_order));
+    refFaceElements.reset(new ReferenceElementSet(final_face_element_type, order, reduced_order));
+    refContactElements.reset(new ReferenceElementSet(contact_element_type, order, reduced_order));
+    refPoints.reset(new ReferenceElementSet(Point1, order, reduced_order));
+    mesh_p->Elements=new ElementFile(refElements, mpi_info);
+    mesh_p->FaceElements=new ElementFile(refFaceElements, mpi_info);
+    mesh_p->ContactElements=new ElementFile(refContactElements, mpi_info);
+    mesh_p->Points=new ElementFile(refPoints, mpi_info);
+
+
+    if (!noError())
+        return ERROR;
+
+    mesh_p->Elements->allocTable(chunkElements);
+    mesh_p->FaceElements->allocTable(chunkFaceElements);
+    mesh_p->ContactElements->allocTable(0);
+    mesh_p->Points->allocTable(0);
+
+    if (!noError())
+        return ERROR;
+
+    mesh_p->Elements->minColor=0;
+    mesh_p->Elements->maxColor=chunkElements-1;
+    mesh_p->FaceElements->minColor=0;
+    mesh_p->FaceElements->maxColor=chunkFaceElements-1;
+    mesh_p->ContactElements->minColor=0;
+    mesh_p->ContactElements->maxColor=0;
+    mesh_p->Points->minColor=0;
+    mesh_p->Points->maxColor=0;
+#pragma omp parallel for schedule(static)
+    for(int e = 0; e < chunkElements; e++) {
+        mesh_p->Elements->Id[e]=id[elementIndices[e]];
+        mesh_p->Elements->Tag[e]=tag[elementIndices[e]];
+        mesh_p->Elements->Color[e]=elementIndices[e];
+        mesh_p->Elements->Owner[e]=mpi_info->rank;
+        for (int j = 0; j < mesh_p->Elements->numNodes; ++j)  {
+            int vertex = vertices[INDEX2(j,elementIndices[e],MAX_numNodes_gmsh)];
+            mesh_p->Elements->Nodes[INDEX2(j, e, mesh_p->Elements->numNodes)]=vertex;
+        }
+    }
+
+#pragma omp parallel for schedule(static)
+    for (int e = 0; e < chunkFaceElements; e++) {
+        mesh_p->FaceElements->Id[e]=id[faceElementIndices[e]];
+        mesh_p->FaceElements->Tag[e]=tag[faceElementIndices[e]];
+        mesh_p->FaceElements->Color[e]=e;
+        mesh_p->FaceElements->Owner[e]=mpi_info->rank;
+        for (int j=0; j<mesh_p->FaceElements->numNodes; ++j) {
+            int faceVertex = vertices[INDEX2(j,faceElementIndices[e],MAX_numNodes_gmsh)];
+            mesh_p->FaceElements->Nodes[INDEX2(j, e, mesh_p->FaceElements->numNodes)]= faceVertex;
+        }
+    }
+
+    /* and clean up */
+    delete[] id;
+    delete[] tag;
+    delete[] element_type;
+    return errorFlag;
+}
+
+int getElementsSlave(esysUtils::JMPI& mpi_info, Mesh *mesh_p, FILE *fileHandle_p,
+        char *error_msg, bool useMacroElements, const std::string fname,
+        int numDim, double version, int order, int reduced_order) {
+    /*
+     *  This function should read in the elements and distribute
+     *  them to the apropriate process.
+     */
+#ifndef ESYS_MPI
+    sprintf(error_msg, "Slave function called in non-MPI build");
+    return THROW_ERROR; // calling the slave from a non-mpi process is an awful idea
+#else
+
+    if (mpi_info->size == 1) {
+        sprintf(error_msg, "Slave function called with no master");
+        return THROW_ERROR; //again, sillyness
+    }
+
+    int errorFlag=0;
+
+    ElementTypeId final_element_type = NoRef;
+    ElementTypeId final_face_element_type = NoRef;
+    ElementTypeId contact_element_type = NoRef;
+    int totalNumElements=0;
+    const_ReferenceElementSet_ptr refPoints, refContactElements;
+    const_ReferenceElementSet_ptr refFaceElements, refElements;
+    ElementTypeId * element_type;
+
+    int msg = 0;
+    MPI_Bcast(&msg, 1, MPI_INT, 0, mpi_info->comm);
+    totalNumElements = msg;
+
+    int chunkSize = totalNumElements / mpi_info->size + 1, chunkElements=0;
+    int chunkFaceElements=0;
+    int *id = new int[chunkSize+1];
+    int *tag = new int[chunkSize+1];
+    std::vector<int>vertices(chunkSize*MAX_numNodes_gmsh, -1);
+    element_type = new ElementTypeId[chunkSize+1];
+    std::vector<int> elementIndices (chunkSize, -1);
+    std::vector<int> faceElementIndices (chunkSize, -1);
+
+    int chunkInfo[2];//chunkInfo stores the number of element and number of face elements
+
+#pragma omp parallel for schedule(static)
+    for (int i=0; i<chunkSize; i++) {
+        id[i] = -1;
+        tag[i] = -1;
+        element_type[i] = NoRef;
+    }
+
+
+    /* Each worker receives messages */
+    MPI_Status status;
+
+    MPI_Recv(&errorFlag, 1, MPI_INT,0, 81719, mpi_info->comm, &status);
+    if (errorFlag) {
+        return errorFlag;
+    }
+    MPI_Recv(&vertices[0], chunkSize*MAX_numNodes_gmsh, MPI_INT, 0, 81720, mpi_info->comm, &status);
+    MPI_Recv(id, chunkSize, MPI_INT, 0, 81721, mpi_info->comm, &status);
+    MPI_Recv(tag, chunkSize, MPI_INT, 0, 81722, mpi_info->comm, &status);
+    MPI_Recv(element_type, chunkSize, MPI_INT, 0, 81723, mpi_info->comm, &status);
+    MPI_Recv(chunkInfo, 2, MPI_INT, 0, 81724, mpi_info->comm, &status);
+    chunkElements = chunkInfo[0];
+    chunkFaceElements = chunkInfo[1];
+    MPI_Recv(&(elementIndices[0]), chunkElements, MPI_INT, 0, 81725, mpi_info->comm,&status);
+    MPI_Recv(&(faceElementIndices[0]), chunkFaceElements, MPI_INT, 0, 81726, mpi_info->comm,&status);
+
+
+    MPI_Bcast(&errorFlag, 1, MPI_INT,  0, mpi_info->comm);
+    if(errorFlag){
+        return errorFlag;
+    }
+
+    // all elements have been read and shared, now we have to identify the
+    // elements for finley
+    if (!noError()) {
+        return ERROR;
+    }
+
+    int numNodes[3] = {0,0,0};
+    MPI_Bcast(numNodes, 3, MPI_INT,  0, mpi_info->comm);
+    final_element_type = static_cast<ElementTypeId>(numNodes[0]);
+    final_face_element_type = static_cast<ElementTypeId>(numNodes[1]);
+    contact_element_type = static_cast<ElementTypeId>(numNodes[2]);
+
+
+
     refElements.reset(new ReferenceElementSet(final_element_type, order, reduced_order));
     refFaceElements.reset(new ReferenceElementSet(final_face_element_type, order, reduced_order));
     refContactElements.reset(new ReferenceElementSet(contact_element_type, order, reduced_order));
@@ -456,11 +582,11 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
     mesh_p->FaceElements=new ElementFile(refFaceElements, mpi_info);
     mesh_p->ContactElements=new ElementFile(refContactElements, mpi_info);
     mesh_p->Points=new ElementFile(refPoints, mpi_info);
-    
+
 
     if (!noError())
         return ERROR;
-    
+
     mesh_p->Elements->allocTable(chunkElements);
     mesh_p->FaceElements->allocTable(chunkFaceElements);
     mesh_p->ContactElements->allocTable(0);
@@ -490,7 +616,7 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
     }
 
 #pragma omp parallel for schedule(static)
-    for (int e = 0; e < chunkFaceElements; e++) {    
+    for (int e = 0; e < chunkFaceElements; e++) {
         mesh_p->FaceElements->Id[e]=id[faceElementIndices[e]];
         mesh_p->FaceElements->Tag[e]=tag[faceElementIndices[e]];
         mesh_p->FaceElements->Color[e]=e;
@@ -506,43 +632,63 @@ int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
     delete[] tag;
     delete[] element_type;
     return errorFlag;
+#endif //#ifndef ESYS_MPI -> #else
+}
+
+int getElements(esysUtils::JMPI& mpi_info, Mesh * mesh_p, FILE * fileHandle_p,
+        char * error_msg, bool useMacroElements, const std::string fname,
+        int numDim, double version, int order, int reduced_order) {
+    if (mpi_info->rank == 0) {
+        return getElementsMaster(mpi_info, mesh_p, fileHandle_p,
+                error_msg, useMacroElements, fname,
+                numDim, version, order, reduced_order);
+    }
+    return getElementsSlave(mpi_info, mesh_p, fileHandle_p,
+                error_msg, useMacroElements, fname,
+                numDim, version, order, reduced_order);
 }
 
 int gather_nodes(FILE *f, std::map<int,int>& tags, char *error_msg,
         int dim, double version, const char *fname)
 {
     int numNodes=0;
-
-    if (fscanf(f, "%d", &numNodes) == EOF)
+    std::vector<char> line;
+    if (!get_line(line, f))
+        return EARLY_EOF;
+    int scan_ret = sscanf(&line[0], "%d", &numNodes);
+    if (scan_ret == EOF)
         return EARLY_EOF;
     for (int node = 0; node < numNodes; node++) {
         int tmp = 0;
-        int scan_ret = fscanf(f, "%d %*e %*e %*e\n", &tmp);
+        std::vector<char> line;
+        if (!get_line(line, f))
+            return EARLY_EOF;
+        int scan_ret = sscanf(&line[0], "%d", &tmp);
         if (scan_ret == EOF) {
             return EARLY_EOF;
         } else if (scan_ret != 1) {
-            sprintf(error_msg, "malformed meshfilea");
+            sprintf(error_msg, "malformed meshfile");
             return THROW_ERROR;
         }
         tags[tmp] = -1;
+
     }
-    char line[LenString_MAX] = {0};
-    if(fgets(line,LenString_MAX,f) == NULL) {
-        return 1;
-    }
-    if (!is_endnode_string(line)) {
-        sprintf(error_msg, "malformed meshfile, expected '$EndNodes', got '%s'", line);
+    if (!get_line(line, f))
+        return EARLY_EOF;
+    if (!is_endnode_string(&line[0])) {
+        sprintf(error_msg, "malformed meshfile, expected '$EndNodes', got '%s'", &line[0]);
         return THROW_ERROR;
     }
-    if(fgets(line,LenString_MAX,f) == NULL) {
-        return 1;
-    }
-    if (strncmp(line, "$ELM", 4) && strncmp(line, "$Elements", 9)) {
-        sprintf(error_msg, "malformed meshfile, expected '$Elements', got '%s'", line);
+    if (!get_line(line, f))
+        return EARLY_EOF;
+    if (strncmp(&line[0], "$ELM", 4) && strncmp(&line[0], "$Elements", 9)) {
+        sprintf(error_msg, "malformed meshfile, expected '$Elements', got '%s'", &line[0]);
         return THROW_ERROR;
     }
     int numElements = -1;
-    int scan_ret = fscanf(f, "%d\n", &numElements);
+    if (!get_line(line, f))
+        return EARLY_EOF;
+    scan_ret = sscanf(&line[0], "%d\n", &numElements);
     if (scan_ret == EOF) {
         return EARLY_EOF;
     } else if (scan_ret != 1) {
@@ -552,13 +698,13 @@ int gather_nodes(FILE *f, std::map<int,int>& tags, char *error_msg,
     struct ElementInfo e;
     std::vector<int> v(MAX_numNodes_gmsh, -1);
     e.vertex = &v[0];
-    
+
     for (int element = 0; element < numElements; element++) {
         getSingleElement(f, dim, version, e, error_msg, fname, false);
         for (int i = 0; i < MAX_numNodes_gmsh && v[i] >= 0; i++) {
             std::map<int,int>::iterator it = tags.find(v[i]);
             if (it == tags.end()) {
-                sprintf(error_msg, "element contains unknown node");
+                sprintf(error_msg, "element contains unknown node (node %d)", v[i]);
                 return THROW_ERROR;
             }
             // the first tagged element using a node tags that node too
@@ -569,96 +715,96 @@ int gather_nodes(FILE *f, std::map<int,int>& tags, char *error_msg,
     return 0;
 }
 
-int getNodes(esysUtils::JMPI& mpi_info, Mesh *mesh_p, FILE *fileHandle_p,
+int getNodesMaster(esysUtils::JMPI& mpi_info, Mesh *mesh_p, FILE *fileHandle_p,
         int numDim, char *error_msg, std::map< int, int>& tags, int errorFlag)
 {
-    int scan_ret, numNodes=0;
-    double rtmp0, rtmp1;
-
-    if (mpi_info->rank == 0) {  /* Master */
-        scan_ret = fscanf(fileHandle_p, "%d", &numNodes);
-        FSCANF_CHECK(scan_ret);
-    }
+    int numNodes=0;
+    std::vector<char> line;
+    if (!get_line(line, fileHandle_p))
+        errorFlag = EARLY_EOF;
+    int scan_ret = sscanf(&line[0], "%d", &numNodes);
+    SSCANF_CHECK(scan_ret);
 #ifdef ESYS_MPI
     // Broadcast numNodes if there are multiple mpi procs
     if (mpi_info->size > 1) {
-        int msg[1];
-        if (mpi_info->rank == 0) {
-            msg[0] = numNodes;
-        } else {
-            msg[0] = 0;
-        }
-        MPI_Bcast(msg, 1, MPI_INT,  0, mpi_info->comm);
-        numNodes = msg[0];
+        MPI_Bcast(&numNodes, 1, MPI_INT,  0, mpi_info->comm);
     }
 #endif
-    int chunkSize = (numNodes / mpi_info->size) + 1, totalNodes=0, chunkNodes=0,  nextCPU=1;
+    int chunkSize;
+    if(mpi_info->size > 1) {
+        chunkSize = (numNodes / mpi_info->size) + 1;
+    } else {
+        chunkSize = (numNodes / mpi_info->size);
+    }
+    int totalNodes=0, chunkNodes = 0;
     int *tempInts = new int[chunkSize+1];        /* Stores the integer message data */
     double *tempCoords = new double[chunkSize*numDim]; /* Stores the double message data */
-    if (mpi_info->rank == 0) {  /* Master */
-        while(1){
+
+    for (int nextCPU = mpi_info->size-1; nextCPU >= 0; nextCPU--) {
+//intialise arrays
 #pragma omp parallel for schedule(static)
-            for (int i=0; i<chunkSize+1; i++)
-                tempInts[i] = -1;
+        for (int i=0; i<chunkSize+1; i++)
+            tempInts[i] = -1;
 #pragma omp parallel for schedule(static)
-            for (int i=0; i<chunkSize*numDim; i++)
-                tempCoords[i] = -1.0;
-
-            if(!errorFlag){
-                chunkNodes=0;
-                for(int i=0;i<chunkSize;i++){
-                    if(totalNodes>=numNodes) break;//sprintf(error_msg, "more "); errorFlag=4;
+        for (int i=0; i<chunkSize*numDim; i++)
+            tempCoords[i] = -1.0;
+        if (!errorFlag) {
+            if (nextCPU ==0) {
+                chunkSize = numNodes-totalNodes;
+            }
+            //read in chunksize nodes
+            for (chunkNodes=0; chunkNodes<chunkSize; chunkNodes++) {
+                if(totalNodes > numNodes) {
+                    sprintf(error_msg, "too many nodes %d > %d", totalNodes, numNodes);
+                    errorFlag = THROW_ERROR;
+                    break;
+                }
+                std::vector<char> line;
+                if (!get_line(line, fileHandle_p))
+                    errorFlag = EARLY_EOF;
+                
+                if (is_endnode_string(&line[0])) {
+                    sprintf(error_msg, "found end node string while still reading nodes");
+                    errorFlag = THROW_ERROR;
+                    break;   
+                } else {
                     if (1 == numDim) {
-                        scan_ret = fscanf(fileHandle_p, "%d %le %le %le\n", &tempInts[i], &tempCoords[0+i*numDim], &rtmp0, &rtmp1);
-                        FSCANF_CHECK(scan_ret);
+                        scan_ret = sscanf(&line[0], "%d %le\n", &tempInts[chunkNodes], &tempCoords[0+chunkNodes*numDim]);
+                        SSCANF_CHECK(scan_ret);
                     } else if (2 == numDim) {
-                        scan_ret = fscanf(fileHandle_p, "%d %le %le %le\n", &tempInts[i], &tempCoords[0+i*numDim], &tempCoords[1+i*numDim], &rtmp1);
-                        FSCANF_CHECK(scan_ret);
+                        scan_ret = sscanf(&line[0], "%d %le %le\n", &tempInts[chunkNodes], &tempCoords[0+chunkNodes*numDim], &tempCoords[1+chunkNodes*numDim]);
+                        SSCANF_CHECK(scan_ret);
                     } else if (3 == numDim) {
-                        scan_ret = fscanf(fileHandle_p, "%d %le %le %le\n", &tempInts[i], &tempCoords[0+i*numDim], &tempCoords[1+i*numDim], &tempCoords[2+i*numDim]);
-                        FSCANF_CHECK(scan_ret);
+                        scan_ret = sscanf(&line[0], "%d %le %le %le\n", &tempInts[chunkNodes], &tempCoords[0+chunkNodes*numDim], &tempCoords[1+chunkNodes*numDim], &tempCoords[2+chunkNodes*numDim]);
+                        SSCANF_CHECK(scan_ret);
                     }
-                    totalNodes++; /* When do we quit the infinite loop? */
-                    chunkNodes++; /* How many nodes do we actually have in this chunk? It may be smaller than chunkSize. */
                 }
+                totalNodes++;
             }
-#ifdef ESYS_MPI
-            if(mpi_info->size>1 && (nextCPU < mpi_info->size)) { 
-                /* Eventually we'll send chunkSize nodes to each CPU numbered 1 ... mpi_info->size-1, here goes one of them */
-                MPI_Send(&errorFlag, 1, MPI_INT, nextCPU, 81719, mpi_info->comm);
-                if(!errorFlag){
-                        tempInts[chunkSize] = chunkNodes;   /* The message has one more int to send chunkNodes */
-                        MPI_Send(tempInts, chunkSize+1, MPI_INT, nextCPU, 81720, mpi_info->comm);
-                        MPI_Send(tempCoords, chunkSize*numDim, MPI_DOUBLE, nextCPU, 81721, mpi_info->comm);
-                }
-            }
-#endif
-            nextCPU++;
-            /* Infinite loop ends when I've read a chunk for each of the worker nodes plus one more chunk for the master */
-            if (nextCPU > mpi_info->size) break; /* End infinite loop */
         }
-    } else {
 #ifdef ESYS_MPI
-        /* Each worker receives two messages */
-        MPI_Status status;
-        MPI_Recv(&errorFlag, 1, MPI_INT,0, 81719, mpi_info->comm, &status);
-        if(!errorFlag){
-            MPI_Recv(tempInts, chunkSize+1, MPI_INT, 0, 81720, mpi_info->comm, &status);
-            MPI_Recv(tempCoords, chunkSize*numDim, MPI_DOUBLE, 0, 81721, mpi_info->comm, &status);
-            chunkNodes = tempInts[chunkSize];   /* How many nodes are in this workers chunk? */
+        if (nextCPU != 0) {
+            /* if there was an error, we have to stop them waiting for more */
+            MPI_Send(&errorFlag, 1, MPI_INT, nextCPU, 81719, mpi_info->comm);
+            /* send out this chunk of mesh to the next waiting node */
+            if (!errorFlag) {
+                tempInts[chunkSize] = chunkNodes;   /* The message has one more int to send chunkNodes */
+                MPI_Send(tempInts, chunkSize+1, MPI_INT, nextCPU, 81720, mpi_info->comm);
+                MPI_Send(tempCoords, chunkSize*numDim, MPI_DOUBLE, nextCPU, 81721, mpi_info->comm);
+            }
         }
 #endif
     }
 
 
-#ifdef ESYS_MPI    
+#ifdef ESYS_MPI
     if(mpi_info->size>1){
         MPI_Bcast(&errorFlag, 1, MPI_INT,  0, mpi_info->comm);
     }
 #endif
     if(errorFlag){
         return errorFlag;
-    }    
+    }
 
     if (!noError()) return ERROR;
     mesh_p->Nodes->allocTable(chunkNodes);
@@ -681,22 +827,163 @@ int getNodes(esysUtils::JMPI& mpi_info, Mesh *mesh_p, FILE *fileHandle_p,
     }
 
     delete[] tempInts;
-    delete[] tempCoords; 
+    delete[] tempCoords;
     return errorFlag;
 }
 
+int getNodesSlave(esysUtils::JMPI& mpi_info, Mesh *mesh_p, FILE *fileHandle_p,
+        int numDim, char *error_msg, std::map< int, int>& tags, int errorFlag)
+{
+#ifndef ESYS_MPI
+    throw FinleyAdapterException("slave function called in non-MPI build");
+#else
+
+    if (mpi_info->size == 1)
+        throw FinleyAdapterException("slave function called without master");
 
+    int numNodes=0;
 
+    // Broadcast numNodes if there are multiple mpi procs
+    MPI_Bcast(&numNodes, 1, MPI_INT,  0, mpi_info->comm);
+    int chunkSize = (numNodes / mpi_info->size) + 1, chunkNodes=0;
+    int *tempInts = new int[chunkSize+1];        /* Stores the integer message data */
+    double *tempCoords = new double[chunkSize*numDim]; /* Stores the double message data */
+    /* Each worker receives two messages */
+    MPI_Status status;
+    MPI_Recv(&errorFlag, 1, MPI_INT,0, 81719, mpi_info->comm, &status);
+    if(!errorFlag){
+        MPI_Recv(tempInts, chunkSize+1, MPI_INT, 0, 81720, mpi_info->comm, &status);
+        MPI_Recv(tempCoords, chunkSize*numDim, MPI_DOUBLE, 0, 81721, mpi_info->comm, &status);
+        chunkNodes = tempInts[chunkSize];   /* How many nodes are in this workers chunk? */
+    }
 
-Mesh* Mesh::readGmsh(esysUtils::JMPI& mpi_info, const std::string fname, int numDim, int order,
+
+    MPI_Bcast(&errorFlag, 1, MPI_INT,  0, mpi_info->comm);
+    if(errorFlag){
+        return errorFlag;
+    }
+
+    if (!noError()) return ERROR;
+    mesh_p->Nodes->allocTable(chunkNodes);
+    if (!noError()) return ERROR;
+
+#pragma omp parallel for schedule(static)
+    for (int i=0; i<chunkNodes; i++) {
+        mesh_p->Nodes->Id[i] = tempInts[i];
+        mesh_p->Nodes->globalDegreesOfFreedom[i] = tempInts[i];
+        int tag = tags[tempInts[i]];
+        if (tag == -1) {
+            mesh_p->Nodes->Tag[i] = tempInts[i]; //set tag to node label
+        } else {
+            mesh_p->Nodes->Tag[i] = tag; //set tag of element
+        }
+        for (int j=0; j<numDim; j++) {
+            mesh_p->Nodes->Coordinates[INDEX2(j,i,numDim)] = tempCoords[i*numDim+j];
+        }
+
+    }
+
+    delete[] tempInts;
+    delete[] tempCoords;
+    return errorFlag;
+#endif //#ifndef ESYS_MPI -> #else
+}
+
+int getNodes(esysUtils::JMPI& mpi_info, Mesh *mesh_p, FILE *fileHandle_p,
+        int numDim, char *error_msg, std::map< int, int>& tags, int errorFlag)
+{
+    if (mpi_info->rank == 0)
+        return getNodesMaster(mpi_info, mesh_p, fileHandle_p, numDim, error_msg,
+                tags, errorFlag);
+
+    return getNodesSlave(mpi_info, mesh_p, fileHandle_p, numDim, error_msg,
+                tags, errorFlag);
+}
+
+int get_next_state(FILE *f, bool nodesRead, bool elementsRead, int *logicFlag) {
+    std::vector<char> line;
+    do {
+        if (!get_line(line, f)) { //got no line
+            //check to see we atleast have some nodes and elements
+            if (!nodesRead) {
+                //EOF before nodes section found
+                return MISSING_NODES;
+            } else if(!elementsRead){
+                //EOF before elements section found
+                return MISSING_ELEMENTS;
+            }
+            return SUCCESS; //EOF as expected
+        }
+//        if (line[0] != '$')
+//            fprintf(stderr, "consuming line: %s", &line[0]);
+    } while(line[0] != '$');
+
+    if (!strncmp(&line[1], "MeshFormat", 10)) {
+        *logicFlag = 1;
+    } else if (is_node_string(&line[0])) {
+        *logicFlag = 2;
+    } else if (!strncmp(&line[1], "ELM", 3) || !strncmp(&line[1], "Elements", 8)) {
+        *logicFlag = 3;
+    } else if (!strncmp(&line[1], "PhysicalNames", 13)) {
+        *logicFlag = 4;
+    }
+    return 0;
+}
+
+void recv_state(esysUtils::JMPI& mpi_info, int *error, int *logic) {
+#ifdef ESYS_MPI
+    int flags[2] = {0};
+    // Broadcast line
+    MPI_Bcast(&flags, 2, MPI_INT, 0, mpi_info->comm);
+    *error = flags[0];
+    if (logic)
+        *logic = flags[1];
+#endif
+}
+
+void send_state(esysUtils::JMPI& mpi_info, int error, int logic) {
+#ifdef ESYS_MPI
+    int flags[2] = {error, logic};
+    // Broadcast line
+    if (mpi_info->size > 1) {
+        MPI_Bcast(&flags, 2, MPI_INT,  0, mpi_info->comm);
+    }
+#endif
+}
+
+int check_error(int error, FILE *f, char *error_msg) {
+        //handle errors
+    switch(error) {
+        case 0:
+            break;
+        case ERROR:
+            throw FinleyAdapterException("ERROR set for unknown reason");
+        case EARLY_EOF: //early eof while scanning
+            throw FinleyAdapterException("early eof while scanning");
+        case MISSING_NODES:  //EOF before nodes section found
+            throw FinleyAdapterException("EOF before nodes section found");
+        case MISSING_ELEMENTS:
+            throw FinleyAdapterException("EOF before elements section found");
+        case THROW_ERROR: // throw error_msg
+            throw FinleyAdapterException(error_msg);
+        case SUCCESS: // eof at apropriate time.
+            if (f)
+                fclose(f);
+            break;
+        default:
+            throw FinleyAdapterException("an unknown error has occured in readGmsh");
+
+    }
+    return error;
+}
+
+Mesh* Mesh::readGmshMaster(esysUtils::JMPI& mpi_info, const std::string fname, int numDim, int order,
                      int reduced_order, bool optimize, bool useMacroElements)
 {
     double version = 1.0;
     bool nodesRead=false, elementsRead=false;
     int format = 0, size = sizeof(double), scan_ret,  errorFlag=0, logicFlag=0;
-    int numNames=0;
-    int i, tag_info[2], itmp;
-    char line[LenString_MAX+1], name[LenString_MAX+1];
+    std::vector<char> line;
     char error_msg[LenErrorMsg_MAX];
     std::map<int,int> nodeTags;
 #ifdef Finley_TRACE
@@ -705,213 +992,235 @@ Mesh* Mesh::readGmsh(esysUtils::JMPI& mpi_info, const std::string fname, int num
     FILE * fileHandle_p = NULL;
 
     resetError();
+    std::size_t found = fname.find("\n");
+    if (found!=std::string::npos){
+        sprintf(error_msg, "file %s contains newline characters.", fname.c_str());
+        errorFlag=THROW_ERROR;
+        send_state(mpi_info, errorFlag, logicFlag);
+        throw FinleyAdapterException(error_msg);
+    }
+
     // allocate mesh
     Mesh* mesh_p = new Mesh(fname, numDim, mpi_info);
 
     // get file handle
-    if (mpi_info->rank == 0) {
-        fileHandle_p = fopen(fname.c_str(), "r");
-        if (fileHandle_p==NULL) {
-            sprintf(error_msg, "Opening Gmsh file %s for reading failed.", fname.c_str());
-            throw FinleyAdapterException(error_msg);
-        }
+    fileHandle_p = fopen(fname.c_str(), "r");
+    if (fileHandle_p==NULL) {
+        sprintf(error_msg, "Opening Gmsh file %s for reading failed.", fname.c_str());
+        errorFlag=THROW_ERROR;
+        send_state(mpi_info, errorFlag, logicFlag);
+        throw FinleyAdapterException(error_msg);
     }
     /* start reading */
     while(noError() && errorFlag==0) {
         /* find line starting with $ */
-        if (mpi_info->rank == 0) {
-            do {
-                if(fgets(line,LenString_MAX,fileHandle_p) == NULL) {
-                    //check to see we atleast have some nodes and elements, if we do end the outer loop otherwise throw early eof.
-                    if (!nodesRead){
-                        //EOF before nodes section found
-                        errorFlag = 2; 
-                    } else if(!elementsRead){
-                        //EOF before elements section found
-                        errorFlag = 3;
-                    } else{
-                        errorFlag=5;
-                    }
-                    break;
-                }
-            } while(line[0] != '$');
-
-            if (!strncmp(&line[1], "MeshFormat", 10)) {
-                logicFlag = 1;
-            }
-
-            else if (is_node_string(line)) {
-                logicFlag = 2;
-            }
-            else if(!strncmp(&line[1], "ELM", 3) ||
-               !strncmp(&line[1], "Elements", 8)  ) {
-                logicFlag = 3;
-            }
-            else if (!strncmp(&line[1], "PhysicalNames", 13)) {
-                logicFlag = 4;
-            }
-        }
-#ifdef ESYS_MPI
-        int flags[2];
-        // Broadcast line
-        if (mpi_info->size > 1) {
-            if (mpi_info -> rank==0) {
-                flags[0] = errorFlag;
-                flags[1] = logicFlag;
-
-            } else {
-                flags[0] = 0;
-                flags[1] = 0;
-            }
-            MPI_Bcast(&flags, 2, MPI_INT,  0, mpi_info->comm);
-            errorFlag = flags[0];
-            logicFlag = flags[1];
-        }
-#endif
-        // MPI_Barrier(mpi_info->comm);
+        logicFlag=0;
+        errorFlag = get_next_state(fileHandle_p, nodesRead, elementsRead, &logicFlag);
+        if (!errorFlag && !noError())
+            errorFlag = ERROR;
+        send_state(mpi_info, errorFlag, logicFlag);
+        //pre-logic error check
+        if (check_error(errorFlag, fileHandle_p, error_msg) == SUCCESS)
+            break;
         /* format */
-        if (mpi_info->rank==0 && logicFlag ==1) {
-                scan_ret = fscanf(fileHandle_p, "%lf %d %d\n", &version, &format, &size);
-                FSCANF_CHECK(scan_ret);
+        if (logicFlag == 1 && errorFlag ==0) {
+            std::vector<char> fmt;
+            if (!get_line(fmt, fileHandle_p))
+                errorFlag = EARLY_EOF;
+            scan_ret = sscanf(&fmt[0], "%lf %d %d\n", &version, &format, &size);
+            SSCANF_CHECK(scan_ret);
         }
         /* nodes are read */
-        else if (logicFlag == 2) {
-
+        else if (logicFlag == 2 && errorFlag ==0) {
             nodesRead=true;
-#ifdef ESYS_MPI
-            int mapsize = 0;
-#endif
             std::vector<int> sendable_map;
-            if (mpi_info->rank == 0) {
-                long current = ftell(fileHandle_p);
-                errorFlag = gather_nodes(fileHandle_p, nodeTags, error_msg,
-                        numDim, version, fname.c_str());
-                if (!errorFlag && fseek(fileHandle_p, current, SEEK_SET) < 0) {
-                        sprintf(error_msg, "Error in file operation");
-                        errorFlag = THROW_ERROR;
-                }
+            long current = ftell(fileHandle_p);
+            errorFlag = gather_nodes(fileHandle_p, nodeTags, error_msg,
+                    numDim, version, fname.c_str());
+            if (!errorFlag && fseek(fileHandle_p, current, SEEK_SET) < 0) {
+                sprintf(error_msg, "Error in file operation");
+                errorFlag = THROW_ERROR;
+            }
+            send_state(mpi_info, errorFlag, logicFlag);
+            check_error(errorFlag, fileHandle_p, error_msg);
 #ifdef ESYS_MPI
-                mapsize = 2*nodeTags.size();
-                sendable_map.resize(mapsize);
-                std::map<int,int>::iterator i = nodeTags.begin();
-                for (int j = 0; i != nodeTags.end(); i++, j += 2) {
-                    sendable_map[j] = i->first;
-                    sendable_map[j + 1] = i->second;
-                }
+            int mapsize = 2*nodeTags.size();
+            sendable_map.resize(mapsize);
+            std::map<int,int>::iterator i = nodeTags.begin();
+            for (int j = 0; i != nodeTags.end(); i++, j += 2) {
+                sendable_map[j] = i->first;
+                sendable_map[j + 1] = i->second;
             }
             if (mpi_info->size > 1) {
                 MPI_Bcast(&mapsize, 1, MPI_INT, 0, mpi_info->comm);
-                if (mpi_info->rank != 0) {
-                    sendable_map.resize(mapsize);
-                }
+                sendable_map.resize(mapsize);
                 MPI_Bcast(&sendable_map[0], mapsize, MPI_INT, 0, mpi_info->comm);
-                if (mpi_info->rank != 0) {
-                    for (int j = 0; j < mapsize; j += 2)
-                        nodeTags[sendable_map[j]] = sendable_map[j + 1];
-                }
-#endif
+                for (int j = 0; j < mapsize; j += 2)
+                    nodeTags[sendable_map[j]] = sendable_map[j + 1];
             }
-
+#endif
             errorFlag = getNodes(mpi_info, mesh_p, fileHandle_p, numDim,
-                    error_msg, nodeTags, errorFlag); 
-            logicFlag=0;
+                    error_msg, nodeTags, errorFlag);
         }
-       
+
         /* elements */
-        else if(logicFlag==3) {
+        else if(logicFlag==3 && errorFlag ==0) {
             elementsRead=true;
-            errorFlag=getElements(mpi_info, mesh_p, fileHandle_p, error_msg, useMacroElements, 
+            errorFlag=getElements(mpi_info, mesh_p, fileHandle_p, error_msg, useMacroElements,
                     fname, numDim, version, order, reduced_order);
-            logicFlag=0;
         }
          /* name tags (thanks to Antoine Lefebvre, antoine.lefebvre2 at mail.mcgill.ca ) */
-        else if (logicFlag==4) {
-            
-            if (! noError()) errorFlag=6;
-            if(mpi_info->rank == 0) {
-                scan_ret = fscanf(fileHandle_p, "%d", &numNames);
-                FSCANF_CHECK(scan_ret);
-            }
+        else if (logicFlag==4 && errorFlag ==0) {
+            if (!noError())
+                errorFlag = ERROR;
+            std::vector<char> names;
+            if (!get_line(names, fileHandle_p))
+                errorFlag = EARLY_EOF;
+            int numNames=0;
+            scan_ret = sscanf(&names[0], "%d", &numNames);
+            SSCANF_CHECK(scan_ret);
 #ifdef ESYS_MPI
-            // Broadcast numNodes if there are multiple mpi procs
+            // Broadcast numNames if there are multiple mpi procs
             if (mpi_info->size > 1) {
                 MPI_Bcast(&numNames, 1, MPI_INT,  0, mpi_info->comm);
             }
 #endif
-
-            for (i = 0; i < numNames; i++) {
-                if(mpi_info->rank == 0) {
-                    scan_ret = fscanf(fileHandle_p, "%d %d %s\n", &itmp, &(tag_info[0]), name);
-                    FSCANF_CHECK(scan_ret);
-                    //if (! (itmp == 2)) setError(IO_ERROR,"Mesh_readGmsh: expecting two entries per physical name.");
-                    if ( strlen(name) < 3 ) setError(IO_ERROR,"Mesh_readGmsh: illegal tagname (\" missing?)");
-                    if (! noError()) errorFlag=6 ;
-                    name[strlen(name)-1]='\0';
-                } 
+            for (int i = 0; i < numNames; i++) {
+                std::vector<char> line;
+                char name[LenString_MAX] = {0};
+                if (!get_line(line, fileHandle_p))
+                    errorFlag = EARLY_EOF;
+                int tag_info[2] = {0};
+                char *position = &line[0];
+                //skip the first int, unsure why
+                if (next_space(&position, 1) == NULL 
+                        || sscanf(position, "%d", tag_info) != 1 
+                        || next_space(&position, 1) == NULL
+                        || sscanf(position, "%s", name) != 1) {
+                    setError(IO_ERROR,"Mesh_readGmsh: bad tagname");
+                }
+                if (!noError())
+                    errorFlag = ERROR;
+                name[strlen(name)-1]='\0'; //strip trailing "
                 //mpi broadcast the tag info
 
 #ifdef ESYS_MPI
                 if (mpi_info->size > 1) {
-                    if(mpi_info->rank==0){
-                        tag_info[1]=strlen(name)+1;
-                    } else{
-                        tag_info[0]=0;
-                        tag_info[1]=0;
-                    }
-
+                    tag_info[1]=strlen(name) + 1; //include \0
                     MPI_Bcast(tag_info, 2, MPI_INT,  0, mpi_info->comm);
-                    MPI_Bcast(&name, tag_info[1], MPI_CHAR,  0, mpi_info->comm); //strlen + 1 for null terminator
+                    MPI_Bcast(&name, tag_info[1], MPI_CHAR,  0, mpi_info->comm);
                 }
-#endif         
-                
-                mesh_p->addTagMap(&name[1], tag_info[0]);
+#endif
+                mesh_p->addTagMap(name+1, tag_info[0]); //skip leading "
 
             }
-            logicFlag=0;
         }
 
-        //read closing tag $EndTHING
-        if(mpi_info->rank==0 && errorFlag!=5) {
-            do {
-                if(fgets(line,LenString_MAX,fileHandle_p) == NULL) {
-                    errorFlag = 1;
-                    break;
-                }
-            } while( line[0]!='$' );
+        if (!get_line(line, fileHandle_p)) {
+            errorFlag = EARLY_EOF;
         }
-
-        //handle errors
-        if(errorFlag){
-            switch(errorFlag) {
-                case 1: //early eof while scanning
-                    throw FinleyAdapterException("early eof while scanning");
-                    break;
-                case 2:  //EOF before nodes section found
-                    throw FinleyAdapterException("EOF before nodes section found");
-                    break;
-                case 3:
-                    throw FinleyAdapterException("EOF before elements section found");
-                    break;
-                case 4: // throw error_msg
-                    throw FinleyAdapterException(error_msg);
-                    break;
-                case 5: // eof at apropriate time.
-                    if(mpi_info->rank == 0) {
-                        fclose(fileHandle_p);
-                    }                    
-                    break;
-                case 6:
-                    // throw FinleyAdapterException("not noError");
-                    return NULL; 
-                default:
-                    throw FinleyAdapterException("an unknown error has occured in readGmsh");
-            }
-            if(errorFlag == 5) {
-                break;
-            }
+        if (line[0] != '$') {
+            errorFlag = THROW_ERROR;
+            snprintf(error_msg, 50, "expected closing tag, got:%s...\n", &line[0]);
         }
+        send_state(mpi_info, errorFlag, logicFlag);
+        //post logic error check, throws if relevant
+        check_error(errorFlag, fileHandle_p, error_msg);
+    }
+    // clean up
+    if (!noError()) {
+        delete mesh_p;
+        return NULL;
+    }    
+    // resolve id's
+    if (noError())
+        mesh_p->resolveNodeIds();
+    // rearrange elements
+    if (noError())
+        mesh_p->prepare(optimize);
+
+    if (!noError()) {
+        delete mesh_p;
+        return NULL;
+    }
+    return mesh_p;
+}
+
+Mesh* Mesh::readGmshSlave(esysUtils::JMPI& mpi_info, const std::string fname, int numDim, int order,
+                     int reduced_order, bool optimize, bool useMacroElements)
+{
+#ifndef ESYS_MPI
+    throw FinleyAdapterException("slave function called in non-MPI build");
+#else
+    if (mpi_info->size == 1)
+        throw FinleyAdapterException("slave function called but only one process");
+
+    double version = 1.0;
+    int errorFlag=0, logicFlag=0;
+    int numNames=0;
+    int i, tag_info[2];
+    char name[LenString_MAX+1];
+    char error_msg[LenErrorMsg_MAX] = {0};
+    std::map<int,int> nodeTags;
+#ifdef Finley_TRACE
+    double time0=timer();
+#endif
+    FILE * fileHandle_p = NULL;
+
+    resetError();
+    // allocate mesh
+    Mesh* mesh_p = new Mesh(fname, numDim, mpi_info);
+
+    // get file handle
+    /* start reading */
+    while(noError() && errorFlag != SUCCESS) {
+        logicFlag = 0;
+        //pre logic state fetch
+        recv_state(mpi_info, &errorFlag, &logicFlag);
+        if (check_error(errorFlag, NULL, error_msg) == SUCCESS)
+            break;
+         
+        /* format */
+        /* nodes are read */
+        if (logicFlag == 2) {
+            int mapsize = 0;
+            std::vector<int> sendable_map;
+            recv_state(mpi_info, &errorFlag, &logicFlag);
+            check_error(errorFlag, NULL, error_msg);
+            MPI_Bcast(&mapsize, 1, MPI_INT, 0, mpi_info->comm);
+            sendable_map.resize(mapsize);
+            MPI_Bcast(&sendable_map[0], mapsize, MPI_INT, 0, mpi_info->comm);
+            for (int j = 0; j < mapsize; j += 2)
+                nodeTags[sendable_map[j]] = sendable_map[j + 1];
 
+            errorFlag = getNodes(mpi_info, mesh_p, fileHandle_p, numDim,
+                    error_msg, nodeTags, errorFlag);
+        }
 
+        /* elements */
+        else if(logicFlag==3) {
+            errorFlag=getElements(mpi_info, mesh_p, fileHandle_p, error_msg, useMacroElements,
+                    fname, numDim, version, order, reduced_order);
+        }
+         /* name tags (thanks to Antoine Lefebvre, antoine.lefebvre2 at mail.mcgill.ca ) */
+        else if (logicFlag==4) {
+            if (! noError())
+                errorFlag = THROW_ERROR;
+            // Broadcast numNames if there are multiple mpi procs
+            MPI_Bcast(&numNames, 1, MPI_INT,  0, mpi_info->comm);
+            for (i = 0; i < numNames; i++) {
+                //mpi broadcast the tag info
+                tag_info[0]=0;
+                tag_info[1]=0;
+                MPI_Bcast(tag_info, 2, MPI_INT,  0, mpi_info->comm);
+                MPI_Bcast(&name, tag_info[1], MPI_CHAR,  0, mpi_info->comm); //strlen + 1 for null terminator
+                mesh_p->addTagMap(&name[1], tag_info[0]);
+            }
+        }
+        //post logic error check
+        recv_state(mpi_info, &errorFlag, &logicFlag);
+        if (check_error(errorFlag, NULL, error_msg) == SUCCESS)
+            break;
     //end while loop
     }
 
@@ -924,7 +1233,7 @@ Mesh* Mesh::readGmsh(esysUtils::JMPI& mpi_info, const std::string fname, int num
     if (noError())
         mesh_p->resolveNodeIds();
     // rearrange elements
-    if (noError()) 
+    if (noError())
         mesh_p->prepare(optimize);
 
     if (!noError()) {
@@ -932,7 +1241,22 @@ Mesh* Mesh::readGmsh(esysUtils::JMPI& mpi_info, const std::string fname, int num
         return NULL;
     }
     return mesh_p;
- }
+#endif //#ifndef ESYS_MPI -> #else
+}
+
+
+
+
+Mesh* Mesh::readGmsh(esysUtils::JMPI& mpi_info, const std::string fname, int numDim, int order,
+                     int reduced_order, bool optimize, bool useMacroElements)
+{
+    if (mpi_info->rank == 0)
+        return readGmshMaster(mpi_info, fname, numDim, order, reduced_order,
+                optimize, useMacroElements);
+
+    return readGmshSlave(mpi_info, fname, numDim, order, reduced_order,
+            optimize, useMacroElements);
+}
 
 } // namespace finley
 
diff --git a/finley/src/Mesh_rec4.cpp b/finley/src/Mesh_rec4.cpp
index d5831a2..e8433f7 100644
--- a/finley/src/Mesh_rec4.cpp
+++ b/finley/src/Mesh_rec4.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -25,6 +25,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "RectangularMesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_rec8.cpp b/finley/src/Mesh_rec8.cpp
index 386cf9f..0f72165 100644
--- a/finley/src/Mesh_rec8.cpp
+++ b/finley/src/Mesh_rec8.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -25,6 +25,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "RectangularMesh.h"
 
 namespace finley {
diff --git a/finley/src/Mesh_write.cpp b/finley/src/Mesh_write.cpp
index c267e2f..b63e934 100644
--- a/finley/src/Mesh_write.cpp
+++ b/finley/src/Mesh_write.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 /************************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Mesh.h"
 
 namespace finley {
diff --git a/finley/src/NodeFile.cpp b/finley/src/NodeFile.cpp
index f646a79..e0c3246 100644
--- a/finley/src/NodeFile.cpp
+++ b/finley/src/NodeFile.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "NodeFile.h"
 #include <escript/Data.h>
 
diff --git a/finley/src/NodeFile.h b/finley/src/NodeFile.h
index 0ed19cd..e256d23 100644
--- a/finley/src/NodeFile.h
+++ b/finley/src/NodeFile.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/NodeMapping.h b/finley/src/NodeMapping.h
index ac99ada..6b8a937 100644
--- a/finley/src/NodeMapping.h
+++ b/finley/src/NodeMapping.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/Quadrature.cpp b/finley/src/Quadrature.cpp
index 104baba..c0ef50c 100644
--- a/finley/src/Quadrature.cpp
+++ b/finley/src/Quadrature.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/Quadrature.h b/finley/src/Quadrature.h
index e08159f..80db8f9 100644
--- a/finley/src/Quadrature.h
+++ b/finley/src/Quadrature.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/RectangularMesh.h b/finley/src/RectangularMesh.h
index 95ed4bf..46c8e2d 100644
--- a/finley/src/RectangularMesh.h
+++ b/finley/src/RectangularMesh.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/ReferenceElementSets.h b/finley/src/ReferenceElementSets.h
index d543268..cd46040 100644
--- a/finley/src/ReferenceElementSets.h
+++ b/finley/src/ReferenceElementSets.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/ReferenceElements.cpp b/finley/src/ReferenceElements.cpp
index b1b2d13..12d831b 100644
--- a/finley/src/ReferenceElements.cpp
+++ b/finley/src/ReferenceElements.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/ReferenceElements.h b/finley/src/ReferenceElements.h
index c17bdd9..a1e2461 100644
--- a/finley/src/ReferenceElements.h
+++ b/finley/src/ReferenceElements.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/SConscript b/finley/src/SConscript
index a3d8973..f495720 100644
--- a/finley/src/SConscript
+++ b/finley/src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/finley/src/ShapeFunctions.cpp b/finley/src/ShapeFunctions.cpp
index 4022425..89f9267 100644
--- a/finley/src/ShapeFunctions.cpp
+++ b/finley/src/ShapeFunctions.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/ShapeFunctions.h b/finley/src/ShapeFunctions.h
index 9936ef6..183e2c9 100644
--- a/finley/src/ShapeFunctions.h
+++ b/finley/src/ShapeFunctions.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/Util.cpp b/finley/src/Util.cpp
index f450bf3..fac9e69 100644
--- a/finley/src/Util.cpp
+++ b/finley/src/Util.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -21,6 +21,9 @@
 
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "Finley.h"
 #include "Util.h"
 #include "esysUtils/index.h"
diff --git a/finley/src/Util.h b/finley/src/Util.h
index 66ee64f..c2ecd5a 100644
--- a/finley/src/Util.h
+++ b/finley/src/Util.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/src/generateReferenceElementList.py b/finley/src/generateReferenceElementList.py
index 5c88663..9f7bdea 100644
--- a/finley/src/generateReferenceElementList.py
+++ b/finley/src/generateReferenceElementList.py
@@ -1,6 +1,6 @@
 #*******************************************************
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/finley/test/MeshAdapterTestCase.cpp b/finley/test/MeshAdapterTestCase.cpp
index f59cfdb..215ce04 100644
--- a/finley/test/MeshAdapterTestCase.cpp
+++ b/finley/test/MeshAdapterTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include "MeshAdapterTestCase.h"
 
diff --git a/finley/test/MeshAdapterTestCase.h b/finley/test/MeshAdapterTestCase.h
index 6a4486b..e1fbed6 100644
--- a/finley/test/MeshAdapterTestCase.h
+++ b/finley/test/MeshAdapterTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/test/SConscript b/finley/test/SConscript
index 2f10752..178447c 100644
--- a/finley/test/SConscript
+++ b/finley/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/finley/test/finley_UnitTests.cpp b/finley/test/finley_UnitTests.cpp
index bfaf265..7da6582 100644
--- a/finley/test/finley_UnitTests.cpp
+++ b/finley/test/finley_UnitTests.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/finley/test/python/FCT_benchmark.py b/finley/test/python/FCT_benchmark.py
index f1b41fc..66ea6d9 100755
--- a/finley/test/python/FCT_benchmark.py
+++ b/finley/test/python/FCT_benchmark.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/FCT_test0.py b/finley/test/python/FCT_test0.py
index 70f9e49..0d33d0d 100644
--- a/finley/test/python/FCT_test0.py
+++ b/finley/test/python/FCT_test0.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/FCT_test1.py b/finley/test/python/FCT_test1.py
index 602a835..aa2a9a4 100644
--- a/finley/test/python/FCT_test1.py
+++ b/finley/test/python/FCT_test1.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/FCT_test2.py b/finley/test/python/FCT_test2.py
index 5cd330a..834fc86 100644
--- a/finley/test/python/FCT_test2.py
+++ b/finley/test/python/FCT_test2.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/OutTest.py b/finley/test/python/OutTest.py
index 20e5e34..d1cab6c 100644
--- a/finley/test/python/OutTest.py
+++ b/finley/test/python/OutTest.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/PoissonSolverTest.py b/finley/test/python/PoissonSolverTest.py
index 36df04f..787fff4 100644
--- a/finley/test/python/PoissonSolverTest.py
+++ b/finley/test/python/PoissonSolverTest.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/RecTest.py b/finley/test/python/RecTest.py
index 7aee03f..a3c8948 100644
--- a/finley/test/python/RecTest.py
+++ b/finley/test/python/RecTest.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/SConscript b/finley/test/python/SConscript
index aa42133..b0eb741 100644
--- a/finley/test/python/SConscript
+++ b/finley/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -46,6 +46,7 @@ testruns += ['run_utilOnFinley.py']
 testruns += ['run_amg.py'] 
 testruns += ['run_nlpde2dOnFinley.py']
 testruns += ['run_nlpde3dOnFinley.py']
+testruns += ['run_splitworldOnFinley.py']
 
 #  files defining a few tests for a quick test
 scalable_tests = []
@@ -79,6 +80,8 @@ env.Alias('scalable_tests', [splitext(x)[0]+'.passed' for x in scalable_tests])
 program = local_env.RunPyUnitTest(alltestruns)
 Depends(program, [py_wrapper_lib, 'install_finley_py'])
 Depends(program, 'build_py_tests')
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # add a group of tests
 from grouptest import *
diff --git a/finley/test/python/axisymm-splitB.py b/finley/test/python/axisymm-splitB.py
index 6d77167..f250954 100755
--- a/finley/test/python/axisymm-splitB.py
+++ b/finley/test/python/axisymm-splitB.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/blocktest.py b/finley/test/python/blocktest.py
index 12226e1..4addb0a 100755
--- a/finley/test/python/blocktest.py
+++ b/finley/test/python/blocktest.py
@@ -12,7 +12,7 @@
 #
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -25,7 +25,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/brick.py b/finley/test/python/brick.py
index 7aab146..9338693 100644
--- a/finley/test/python/brick.py
+++ b/finley/test/python/brick.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/coalgas.py b/finley/test/python/coalgas.py
index 805b450..89075bf 100755
--- a/finley/test/python/coalgas.py
+++ b/finley/test/python/coalgas.py
@@ -1,6 +1,6 @@
 ######################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 """
 Gas in Coal Seam (fully coupled version)
 """
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/convection.py b/finley/test/python/convection.py
index c1c34ac..573428e 100644
--- a/finley/test/python/convection.py
+++ b/finley/test/python/convection.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -18,7 +18,7 @@ this is a convection simulation over a domain [0,L] X [0,L] x [0,H]
 It is solved in dimensionless form
 
 """
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/damage.py b/finley/test/python/damage.py
index 81ca6bb..7b64803 100644
--- a/finley/test/python/damage.py
+++ b/finley/test/python/damage.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 """
 Damage mechanics 
 """
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/generate_dumps.py b/finley/test/python/generate_dumps.py
index 5e84ead..d2ef522 100644
--- a/finley/test/python/generate_dumps.py
+++ b/finley/test/python/generate_dumps.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/generate_meshes.py b/finley/test/python/generate_meshes.py
index c40b880..3aacb1c 100644
--- a/finley/test/python/generate_meshes.py
+++ b/finley/test/python/generate_meshes.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/linearElastic.py b/finley/test/python/linearElastic.py
index b94d9ef..205994e 100755
--- a/finley/test/python/linearElastic.py
+++ b/finley/test/python/linearElastic.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/localization.py b/finley/test/python/localization.py
index 0f2a51b..4d2433b 100644
--- a/finley/test/python/localization.py
+++ b/finley/test/python/localization.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -18,7 +18,7 @@ with a plastic layer above a viscous layer of thickness H_VISC.
 The yield condition is perturbed along a line at the boundary between
 viscous and plastic layer to trigger localization.
 """
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/lumping_advection_test.py b/finley/test/python/lumping_advection_test.py
index f740df3..e0d0c72 100755
--- a/finley/test/python/lumping_advection_test.py
+++ b/finley/test/python/lumping_advection_test.py
@@ -6,7 +6,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -19,7 +19,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/lumping_wave_test.py b/finley/test/python/lumping_wave_test.py
index 971d1b2..7817c74 100755
--- a/finley/test/python/lumping_wave_test.py
+++ b/finley/test/python/lumping_wave_test.py
@@ -6,7 +6,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -19,7 +19,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/rayleigh_taylor_instabilty.py b/finley/test/python/rayleigh_taylor_instabilty.py
index 1df68f1..42fad15 100644
--- a/finley/test/python/rayleigh_taylor_instabilty.py
+++ b/finley/test/python/rayleigh_taylor_instabilty.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/rectangle.py b/finley/test/python/rectangle.py
index 30ac9be..41a5075 100644
--- a/finley/test/python/rectangle.py
+++ b/finley/test/python/rectangle.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/run_amg.py b/finley/test/python/run_amg.py
index 4b22928..ac2b80c 100644
--- a/finley/test/python/run_amg.py
+++ b/finley/test/python/run_amg.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/run_darcy.py b/finley/test/python/run_darcy.py
index 305ae10..e042041 100644
--- a/finley/test/python/run_darcy.py
+++ b/finley/test/python/run_darcy.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/run_escriptOnFinley.py b/finley/test/python/run_escriptOnFinley.py
index 489b791..cdddc6e 100644
--- a/finley/test/python/run_escriptOnFinley.py
+++ b/finley/test/python/run_escriptOnFinley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -194,6 +194,10 @@ class Test_OtherInterpolationOnFinley(unittest.TestCase):
         
 class Test_CSVOnFinley(Test_saveCSV):
     def setUp(self):
+        try:
+           self.workdir=os.environ['FINLEY_WORKDIR']
+        except KeyError:
+           self.workdir='.'
         NE0=NE
         NE1=NE+1
         self.domain = Rectangle(NE0, NE1, order=2)
@@ -224,7 +228,7 @@ class Test_CSVOnFinley(Test_saveCSV):
 
     @unittest.skipIf(mpisize>1, "more than 1 MPI rank")
     def test_csv_multiFS(self):
-        fname=os.path.join(FINLEY_WORKDIR, "test_multifs.csv")
+        fname=os.path.join(self.workdir, "test_multifs.csv")
         sol=Data(8,Solution(self.domain))
         ctsfn=Data(9,ContinuousFunction(self.domain))
         #test line 0
diff --git a/finley/test/python/run_generators.py b/finley/test/python/run_generators.py
index 75865f6..2671ff5 100644
--- a/finley/test/python/run_generators.py
+++ b/finley/test/python/run_generators.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/run_inputOutput.py b/finley/test/python/run_inputOutput.py
index 11ea457..29555cb 100644
--- a/finley/test/python/run_inputOutput.py
+++ b/finley/test/python/run_inputOutput.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/run_linearPDEsOnFinley1_2D1.py b/finley/test/python/run_linearPDEsOnFinley1_2D1.py
index 16a3f1a..b1a1a31 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_2D1.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_2D1.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_2D2.py b/finley/test/python/run_linearPDEsOnFinley1_2D2.py
index 203cace..4b83102 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_2D2.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_2D2.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D1.py b/finley/test/python/run_linearPDEsOnFinley1_3D1.py
index e8da808..6626d3b 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D1.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D1.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part1.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part1.py
index 348c04b..d2e3d57 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part1.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part1.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part2.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part2.py
index 1d5c903..a179998 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part2.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part2.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-1.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-1.py
index d276fbe..ef201ec 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-1.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-1.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-2.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-2.py
index c386755..f4a52a3 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-2.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-2.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-3.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-3.py
index 2edad82..8a566d9 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-3.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-3.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-4.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-4.py
index aa2b2c9..b5a92b1 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-4.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part3-4.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley1_3D2_part4.py b/finley/test/python/run_linearPDEsOnFinley1_3D2_part4.py
index 048ec54..866681e 100644
--- a/finley/test/python/run_linearPDEsOnFinley1_3D2_part4.py
+++ b/finley/test/python/run_linearPDEsOnFinley1_3D2_part4.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley2.py b/finley/test/python/run_linearPDEsOnFinley2.py
index d634d1a..e95d177 100644
--- a/finley/test/python/run_linearPDEsOnFinley2.py
+++ b/finley/test/python/run_linearPDEsOnFinley2.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinley3.py b/finley/test/python/run_linearPDEsOnFinley3.py
index cdf8355..489fff4 100644
--- a/finley/test/python/run_linearPDEsOnFinley3.py
+++ b/finley/test/python/run_linearPDEsOnFinley3.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_linearPDEsOnFinleyMacro.py b/finley/test/python/run_linearPDEsOnFinleyMacro.py
index 8a65c94..680277f 100644
--- a/finley/test/python/run_linearPDEsOnFinleyMacro.py
+++ b/finley/test/python/run_linearPDEsOnFinleyMacro.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_models.py b/finley/test/python/run_models.py
index f4437e2..df14aa8 100644
--- a/finley/test/python/run_models.py
+++ b/finley/test/python/run_models.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/run_nlpde2dOnFinley.py b/finley/test/python/run_nlpde2dOnFinley.py
index f4e43df..be96595 100644
--- a/finley/test/python/run_nlpde2dOnFinley.py
+++ b/finley/test/python/run_nlpde2dOnFinley.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_nlpde3dOnFinley.py b/finley/test/python/run_nlpde3dOnFinley.py
index 3cadbe3..277b409 100644
--- a/finley/test/python/run_nlpde3dOnFinley.py
+++ b/finley/test/python/run_nlpde3dOnFinley.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/finley/test/python/run_simplesolve.py b/finley/test/python/run_simplesolve.py
index 2ec5282..95a6d78 100644
--- a/finley/test/python/run_simplesolve.py
+++ b/finley/test/python/run_simplesolve.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/escriptcore/test/python/run_testdomain.py b/finley/test/python/run_splitworldOnFinley.py
similarity index 60%
copy from escriptcore/test/python/run_testdomain.py
copy to finley/test/python/run_splitworldOnFinley.py
index f625275..095f581 100644
--- a/escriptcore/test/python/run_testdomain.py
+++ b/finley/test/python/run_splitworldOnFinley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2012-2014 by University of Queensland
+# Copyright (c) 2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2012-2014 by University of Queensland
+__copyright__="""Copyright (c) 2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -23,20 +23,23 @@ __url__="https://launchpad.net/escript-finley"
 
 import esys.escriptcore.utestselect as unittest
 from esys.escriptcore.testing import *
-import sys
 from esys.escript import *
+from esys.finley import Rectangle, Brick, ReadMesh, ReadGmsh
+from test_splitworld import Test_SplitWorld
+
+
+mpisize=getMPISizeWorld()
+NE=4 # number elements, must be even
+
+class Test_SplitOnFinley(Test_SplitWorld):
+  def setUp(self):
+    self.domainpars=[Rectangle, NE, NE]
+    
+  def tearDown(self):
+    del self.domainpars
+
 
-class TestDomainTests(unittest.TestCase):
-    TOL=EPSILON*100.
-    def testreduction(self):
-        dom = getTestDomainFunctionSpace(4,2,2).getDomain()
-        dx=dom.getX()
-        msk_arg=whereNegative(dx[0]-0.5)
-        arg=msk_arg*numpy.array([-0.5, -0.84])+(1.-msk_arg)*numpy.array([-0.72, 0.9])
-        res=maxval(arg)
-        msk_ref=whereNegative(dx[0]-0.5)
-        ref=msk_ref*(-0.5)+(1.-msk_ref)*0.9
-        self.assertTrue(Lsup(res-ref) <= self.TOL, "ReductionOnTestDomain Failed")
 
 if __name__ == '__main__':
     run_tests(__name__, exit_on_failure=True)
+
diff --git a/finley/test/python/run_utilOnFinley.py b/finley/test/python/run_utilOnFinley.py
index e06328d..dfb2b52 100644
--- a/finley/test/python/run_utilOnFinley.py
+++ b/finley/test/python/run_utilOnFinley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -52,6 +52,10 @@ NE=4 # number elements, must be even
 
 class Test_UtilOnFinley(Test_util,Test_symfuncs,Test_util_NaN_funcs):
    def setUp(self):
+       try:
+           self.workdir=os.environ['FINLEY_WORKDIR']
+       except KeyError:
+           self.workdir='.'
        self.domain =Rectangle(NE,NE+1,2)
        self.functionspace = FunctionOnBoundary(self.domain) # due to a bug in escript python needs to hold a reference to the domain
    def tearDown(self):
diff --git a/finley/test/python/run_visualization_interface.py b/finley/test/python/run_visualization_interface.py
index 6ade0a4..387e031 100644
--- a/finley/test/python/run_visualization_interface.py
+++ b/finley/test/python/run_visualization_interface.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/runcoalgas.py b/finley/test/python/runcoalgas.py
index 307763d..b2aca86 100755
--- a/finley/test/python/runcoalgas.py
+++ b/finley/test/python/runcoalgas.py
@@ -1,6 +1,6 @@
 #######################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 """
 Coal Seam gasL ECLIPSE test case
 """
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/seismic_wave.py b/finley/test/python/seismic_wave.py
index e400ca0..8d999b6 100644
--- a/finley/test/python/seismic_wave.py
+++ b/finley/test/python/seismic_wave.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/slip_stress_mesh_old.py b/finley/test/python/slip_stress_mesh_old.py
index 7bafad8..940b1b1 100644
--- a/finley/test/python/slip_stress_mesh_old.py
+++ b/finley/test/python/slip_stress_mesh_old.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/slip_stress_old.py b/finley/test/python/slip_stress_old.py
index 5d59f3f..9c7b56d 100644
--- a/finley/test/python/slip_stress_old.py
+++ b/finley/test/python/slip_stress_old.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/stokes_problems.py b/finley/test/python/stokes_problems.py
index 70b9faf..4848e59 100644
--- a/finley/test/python/stokes_problems.py
+++ b/finley/test/python/stokes_problems.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/subduction1.py b/finley/test/python/subduction1.py
index aa2525b..5cf4f60 100644
--- a/finley/test/python/subduction1.py
+++ b/finley/test/python/subduction1.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/subduction1_gen.py b/finley/test/python/subduction1_gen.py
index 79448cf..f404d08 100644
--- a/finley/test/python/subduction1_gen.py
+++ b/finley/test/python/subduction1_gen.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/time_chunks.py b/finley/test/python/time_chunks.py
index 14433a5..6d5a872 100644
--- a/finley/test/python/time_chunks.py
+++ b/finley/test/python/time_chunks.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/finley/test/python/tp.py b/finley/test/python/tp.py
index 85469aa..926c565 100644
--- a/finley/test/python/tp.py
+++ b/finley/test/python/tp.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/SConscript b/modellib/py_src/SConscript
index 969feb7..7da5cf2 100644
--- a/modellib/py_src/SConscript
+++ b/modellib/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/modellib/py_src/flow.py b/modellib/py_src/flow.py
index 4fada16..ee4553e 100644
--- a/modellib/py_src/flow.py
+++ b/modellib/py_src/flow.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/geometry.py b/modellib/py_src/geometry.py
index 0677a04..ad50c2f 100644
--- a/modellib/py_src/geometry.py
+++ b/modellib/py_src/geometry.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/input.py b/modellib/py_src/input.py
index 76e4e62..75db419 100644
--- a/modellib/py_src/input.py
+++ b/modellib/py_src/input.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/materials.py b/modellib/py_src/materials.py
index f9d02ce..6e54120 100644
--- a/modellib/py_src/materials.py
+++ b/modellib/py_src/materials.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/mechanics.py b/modellib/py_src/mechanics.py
index 9f45e39..e729f0d 100644
--- a/modellib/py_src/mechanics.py
+++ b/modellib/py_src/mechanics.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/probe.py b/modellib/py_src/probe.py
index 9e310c7..1767e33 100644
--- a/modellib/py_src/probe.py
+++ b/modellib/py_src/probe.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/temperature.py b/modellib/py_src/temperature.py
index 59958a4..51ec3cd 100644
--- a/modellib/py_src/temperature.py
+++ b/modellib/py_src/temperature.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/tsunami.py.old b/modellib/py_src/tsunami.py.old
index 1a4d665..5082662 100644
--- a/modellib/py_src/tsunami.py.old
+++ b/modellib/py_src/tsunami.py.old
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2012 by University of Queensland
+# Copyright (c) 2003-2012 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2012 by University of Queensland
+__copyright__="""Copyright (c) 2003-2012 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/py_src/visualization.py b/modellib/py_src/visualization.py
index 0cccb59..a631fb4 100644
--- a/modellib/py_src/visualization.py
+++ b/modellib/py_src/visualization.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/test/python/SConscript b/modellib/test/python/SConscript
index dcd7add..1644e7d 100644
--- a/modellib/test/python/SConscript
+++ b/modellib/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/modellib/test/python/drucker_prager.py b/modellib/test/python/drucker_prager.py
index 7ba94f9..d041961 100644
--- a/modellib/test/python/drucker_prager.py
+++ b/modellib/test/python/drucker_prager.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/test/python/run_convection.py b/modellib/test/python/run_convection.py
index 4deee97..f1fa172 100644
--- a/modellib/test/python/run_convection.py
+++ b/modellib/test/python/run_convection.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/test/python/run_domainreaders.py b/modellib/test/python/run_domainreaders.py
index b935851..0932358 100644
--- a/modellib/test/python/run_domainreaders.py
+++ b/modellib/test/python/run_domainreaders.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@ from __future__ import print_function
 
 from __future__ import print_function
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/test/python/run_flow.py b/modellib/test/python/run_flow.py
index e8fdb39..e908a78 100644
--- a/modellib/test/python/run_flow.py
+++ b/modellib/test/python/run_flow.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@ from __future__ import print_function
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/modellib/test/python/run_temp.py b/modellib/test/python/run_temp.py
index 91e3473..75f500d 100644
--- a/modellib/test/python/run_temp.py
+++ b/modellib/test/python/run_temp.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/paso/profiling/Paso_tests.cpp b/paso/profiling/Paso_tests.cpp
index e4ee4cb..045d99c 100644
--- a/paso/profiling/Paso_tests.cpp
+++ b/paso/profiling/Paso_tests.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/profiling/Paso_tests.h b/paso/profiling/Paso_tests.h
index b1634b2..1977dfc 100644
--- a/paso/profiling/Paso_tests.h
+++ b/paso/profiling/Paso_tests.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/profiling/SConscript b/paso/profiling/SConscript
index d05c753..3115700 100644
--- a/paso/profiling/SConscript
+++ b/paso/profiling/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/paso/src/AMG.cpp b/paso/src/AMG.cpp
index eccece6..8af0048 100644
--- a/paso/src/AMG.cpp
+++ b/paso/src/AMG.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/AMG_Interpolation.cpp b/paso/src/AMG_Interpolation.cpp
index 96be1a8..cd696cc 100644
--- a/paso/src/AMG_Interpolation.cpp
+++ b/paso/src/AMG_Interpolation.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/AMG_Prolongation.cpp b/paso/src/AMG_Prolongation.cpp
index 667c853..6ec2a9b 100644
--- a/paso/src/AMG_Prolongation.cpp
+++ b/paso/src/AMG_Prolongation.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/AMG_Restriction.cpp b/paso/src/AMG_Restriction.cpp
index ca09a80..7e3456e 100644
--- a/paso/src/AMG_Restriction.cpp
+++ b/paso/src/AMG_Restriction.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/AMG_Root.cpp b/paso/src/AMG_Root.cpp
index a5a7864..7690666 100644
--- a/paso/src/AMG_Root.cpp
+++ b/paso/src/AMG_Root.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/AML.cpp.old b/paso/src/AML.cpp.old
index 35e8fb0..73a993f 100644
--- a/paso/src/AML.cpp.old
+++ b/paso/src/AML.cpp.old
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -558,7 +558,7 @@ void Solver_solveAMLI(Solver_AMLI * amli, double * x, double * b) {
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/BOOMERAMG.cpp b/paso/src/BOOMERAMG.cpp
index bd45643..a56a3af 100644
--- a/paso/src/BOOMERAMG.cpp
+++ b/paso/src/BOOMERAMG.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/BOOMERAMG.h b/paso/src/BOOMERAMG.h
index 95124a4..896efc7 100644
--- a/paso/src/BOOMERAMG.h
+++ b/paso/src/BOOMERAMG.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/BiCGStab.cpp b/paso/src/BiCGStab.cpp
index 73f0668..839b4d6 100644
--- a/paso/src/BiCGStab.cpp
+++ b/paso/src/BiCGStab.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/BlockOps.h b/paso/src/BlockOps.h
index d5e0795..12bacd3 100644
--- a/paso/src/BlockOps.h
+++ b/paso/src/BlockOps.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Coupler.cpp b/paso/src/Coupler.cpp
index bcb513a..de47fd1 100644
--- a/paso/src/Coupler.cpp
+++ b/paso/src/Coupler.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Coupler.h b/paso/src/Coupler.h
index 62c3209..500c9a9 100644
--- a/paso/src/Coupler.h
+++ b/paso/src/Coupler.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Distribution.cpp b/paso/src/Distribution.cpp
index a51ccfb..2ac2975 100644
--- a/paso/src/Distribution.cpp
+++ b/paso/src/Distribution.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Distribution.h b/paso/src/Distribution.h
index fac3aad..5e6e2b3 100644
--- a/paso/src/Distribution.h
+++ b/paso/src/Distribution.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/FCT_Solver.cpp b/paso/src/FCT_Solver.cpp
index 84ec4d2..6e278d2 100644
--- a/paso/src/FCT_Solver.cpp
+++ b/paso/src/FCT_Solver.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/FCT_Solver.h b/paso/src/FCT_Solver.h
index 8292b0e..17f7c91 100644
--- a/paso/src/FCT_Solver.h
+++ b/paso/src/FCT_Solver.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/FluxLimiter.cpp b/paso/src/FluxLimiter.cpp
index e17066c..5e5e112 100644
--- a/paso/src/FluxLimiter.cpp
+++ b/paso/src/FluxLimiter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/FluxLimiter.h b/paso/src/FluxLimiter.h
index e3529a4..cdb7322 100644
--- a/paso/src/FluxLimiter.h
+++ b/paso/src/FluxLimiter.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Functions.cpp b/paso/src/Functions.cpp
index 900d012..5e0e275 100644
--- a/paso/src/Functions.cpp
+++ b/paso/src/Functions.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Functions.h b/paso/src/Functions.h
index 0dc357b..519b2bc 100644
--- a/paso/src/Functions.h
+++ b/paso/src/Functions.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/GMRES.cpp b/paso/src/GMRES.cpp
index 6f2412e..da3aac6 100644
--- a/paso/src/GMRES.cpp
+++ b/paso/src/GMRES.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/GMRES2.cpp b/paso/src/GMRES2.cpp
index 681bfca..d9b5dbe 100644
--- a/paso/src/GMRES2.cpp
+++ b/paso/src/GMRES2.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/GSMPI.cpp.old b/paso/src/GSMPI.cpp.old
index bc434a2..cb4ab1d 100644
--- a/paso/src/GSMPI.cpp.old
+++ b/paso/src/GSMPI.cpp.old
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/ILU.cpp b/paso/src/ILU.cpp
index 4b17240..c7637af 100644
--- a/paso/src/ILU.cpp
+++ b/paso/src/ILU.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/LocalAMG.cpp b/paso/src/LocalAMG.cpp
index 069af15..78b104b 100644
--- a/paso/src/LocalAMG.cpp
+++ b/paso/src/LocalAMG.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/LocalAMG_Prolongation.cpp b/paso/src/LocalAMG_Prolongation.cpp
index 16bafd8..8a1392a 100644
--- a/paso/src/LocalAMG_Prolongation.cpp
+++ b/paso/src/LocalAMG_Prolongation.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/MINRES.cpp b/paso/src/MINRES.cpp
index 6144789..1aa749d 100644
--- a/paso/src/MINRES.cpp
+++ b/paso/src/MINRES.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/MKL.cpp b/paso/src/MKL.cpp
index dca721b..174dc7e 100644
--- a/paso/src/MKL.cpp
+++ b/paso/src/MKL.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/MKL.h b/paso/src/MKL.h
index 8399ce1..e6622a5 100644
--- a/paso/src/MKL.h
+++ b/paso/src/MKL.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/MergedSolver.cpp b/paso/src/MergedSolver.cpp
index 022f229..ca4e5dc 100644
--- a/paso/src/MergedSolver.cpp
+++ b/paso/src/MergedSolver.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/MergedSolver.h b/paso/src/MergedSolver.h
index 745171e..ce0134d 100644
--- a/paso/src/MergedSolver.h
+++ b/paso/src/MergedSolver.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/NewtonGMRES.cpp b/paso/src/NewtonGMRES.cpp
index 6a21132..9d7ab62 100644
--- a/paso/src/NewtonGMRES.cpp
+++ b/paso/src/NewtonGMRES.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Options.cpp b/paso/src/Options.cpp
index 9c1c577..6b88612 100644
--- a/paso/src/Options.cpp
+++ b/paso/src/Options.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Options.h b/paso/src/Options.h
index ebcff96..2f4f17d 100644
--- a/paso/src/Options.h
+++ b/paso/src/Options.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/PCG.cpp b/paso/src/PCG.cpp
index 40bb977..281d933 100644
--- a/paso/src/PCG.cpp
+++ b/paso/src/PCG.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Paso.h b/paso/src/Paso.h
index d9fb2e4..44658ff 100644
--- a/paso/src/Paso.h
+++ b/paso/src/Paso.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/PasoUtil.cpp b/paso/src/PasoUtil.cpp
index 001c78f..04e3f13 100644
--- a/paso/src/PasoUtil.cpp
+++ b/paso/src/PasoUtil.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/PasoUtil.h b/paso/src/PasoUtil.h
index 5ab6e04..cadef29 100644
--- a/paso/src/PasoUtil.h
+++ b/paso/src/PasoUtil.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Pattern.cpp b/paso/src/Pattern.cpp
index 727439b..67bca6b 100644
--- a/paso/src/Pattern.cpp
+++ b/paso/src/Pattern.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Pattern.h b/paso/src/Pattern.h
index 5b5809f..ba52ef0 100644
--- a/paso/src/Pattern.h
+++ b/paso/src/Pattern.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Pattern_mis.cpp b/paso/src/Pattern_mis.cpp
index af58769..fcdc4cf 100644
--- a/paso/src/Pattern_mis.cpp
+++ b/paso/src/Pattern_mis.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Pattern_reduceBandwidth.cpp b/paso/src/Pattern_reduceBandwidth.cpp
index e6eb2ea..3f1dadd 100644
--- a/paso/src/Pattern_reduceBandwidth.cpp
+++ b/paso/src/Pattern_reduceBandwidth.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Preconditioner.cpp b/paso/src/Preconditioner.cpp
index 0d691f2..26944f8 100644
--- a/paso/src/Preconditioner.cpp
+++ b/paso/src/Preconditioner.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Preconditioner.h b/paso/src/Preconditioner.h
index a95c5dd..a4b4c65 100644
--- a/paso/src/Preconditioner.h
+++ b/paso/src/Preconditioner.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/RILU.cpp b/paso/src/RILU.cpp
index 7ab8dd1..c4cf298 100644
--- a/paso/src/RILU.cpp
+++ b/paso/src/RILU.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/ReactiveSolver.cpp b/paso/src/ReactiveSolver.cpp
index b47ba21..c441e10 100644
--- a/paso/src/ReactiveSolver.cpp
+++ b/paso/src/ReactiveSolver.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/ReactiveSolver.h b/paso/src/ReactiveSolver.h
index 60e7ef3..cf9bd91 100644
--- a/paso/src/ReactiveSolver.h
+++ b/paso/src/ReactiveSolver.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SConscript b/paso/src/SConscript
index ebdc23a..8300a1e 100644
--- a/paso/src/SConscript
+++ b/paso/src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/paso/src/SchurComplement.cpp b/paso/src/SchurComplement.cpp
index 059664e..97b0bed 100644
--- a/paso/src/SchurComplement.cpp
+++ b/paso/src/SchurComplement.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SharedComponents.h b/paso/src/SharedComponents.h
index 3453990..559bb5e 100644
--- a/paso/src/SharedComponents.h
+++ b/paso/src/SharedComponents.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Smoother.cpp b/paso/src/Smoother.cpp
index 8a6d7b0..8bd5376 100644
--- a/paso/src/Smoother.cpp
+++ b/paso/src/Smoother.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Solver.cpp b/paso/src/Solver.cpp
index c0c40e1..d1830c0 100644
--- a/paso/src/Solver.cpp
+++ b/paso/src/Solver.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -24,12 +24,16 @@
 /* Author: Lutz Gross, l.gross at uq.edu.au                      */
 
 /****************************************************************************/
+#include <boost/math/special_functions/fpclassify.hpp>  // for isnan
+
 #include <iostream>
 #include "Paso.h"
 #include "SystemMatrix.h"
 #include "Solver.h"
 #include "esysUtils/blocktimer.h"
 
+namespace bm=boost::math;
+
 namespace paso {
 
 void Solver_free(SystemMatrix* A)
@@ -127,7 +131,7 @@ void Solver(SystemMatrix_ptr A, double* x, double* b, Options* options,
 #endif
         norm2_of_b=sqrt(norm2_of_b);
         /* if norm2_of_b==0 we are ready: x=0 */
-        if (IS_NAN(norm2_of_b) || IS_NAN(norm_max_of_b)) {
+        if (bm::isnan(norm2_of_b) || bm::isnan(norm_max_of_b)) {
             Esys_setError(VALUE_ERROR, "Solver: Matrix or right hand side contains undefined values.");
         } else if (norm2_of_b <= 0.) {
 #pragma omp parallel for private(i) schedule(static)
diff --git a/paso/src/Solver.h b/paso/src/Solver.h
index 082caac..4eeb6d9 100644
--- a/paso/src/Solver.h
+++ b/paso/src/Solver.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Solver_Function.cpp b/paso/src/Solver_Function.cpp
index 119e250..da3c550 100644
--- a/paso/src/Solver_Function.cpp
+++ b/paso/src/Solver_Function.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Solver_applyBlockDiagonalMatrix.cpp.old b/paso/src/Solver_applyBlockDiagonalMatrix.cpp.old
index 8a1ad99..fc0bb3e 100644
--- a/paso/src/Solver_applyBlockDiagonalMatrix.cpp.old
+++ b/paso/src/Solver_applyBlockDiagonalMatrix.cpp.old
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix.cpp b/paso/src/SparseMatrix.cpp
index 50899b9..87d78d3 100644
--- a/paso/src/SparseMatrix.cpp
+++ b/paso/src/SparseMatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix.h b/paso/src/SparseMatrix.h
index 6481166..e0f8886 100644
--- a/paso/src/SparseMatrix.h
+++ b/paso/src/SparseMatrix.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix_MatrixMatrix.cpp b/paso/src/SparseMatrix_MatrixMatrix.cpp
index 129b89b..0264916 100644
--- a/paso/src/SparseMatrix_MatrixMatrix.cpp
+++ b/paso/src/SparseMatrix_MatrixMatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix_MatrixMatrixTranspose.cpp b/paso/src/SparseMatrix_MatrixMatrixTranspose.cpp
index 20db8a1..e8ee7f2 100644
--- a/paso/src/SparseMatrix_MatrixMatrixTranspose.cpp
+++ b/paso/src/SparseMatrix_MatrixMatrixTranspose.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix_MatrixVector.cpp b/paso/src/SparseMatrix_MatrixVector.cpp
index feca3be..e82fd12 100644
--- a/paso/src/SparseMatrix_MatrixVector.cpp
+++ b/paso/src/SparseMatrix_MatrixVector.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix_getSubmatrix.cpp b/paso/src/SparseMatrix_getSubmatrix.cpp
index 55e406e..3bf9a74 100644
--- a/paso/src/SparseMatrix_getSubmatrix.cpp
+++ b/paso/src/SparseMatrix_getSubmatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix_nullifyRowsAndCols.cpp b/paso/src/SparseMatrix_nullifyRowsAndCols.cpp
index d5216e7..6452a4c 100644
--- a/paso/src/SparseMatrix_nullifyRowsAndCols.cpp
+++ b/paso/src/SparseMatrix_nullifyRowsAndCols.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SparseMatrix_saveHB.cpp b/paso/src/SparseMatrix_saveHB.cpp
index 4aae806..ea3a384 100644
--- a/paso/src/SparseMatrix_saveHB.cpp
+++ b/paso/src/SparseMatrix_saveHB.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix.cpp b/paso/src/SystemMatrix.cpp
index 2316f9b..7bcdeb0 100644
--- a/paso/src/SystemMatrix.cpp
+++ b/paso/src/SystemMatrix.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix.h b/paso/src/SystemMatrix.h
index e0bfa10..31b9c98 100644
--- a/paso/src/SystemMatrix.h
+++ b/paso/src/SystemMatrix.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrixPattern.cpp b/paso/src/SystemMatrixPattern.cpp
index e5bd1dd..9614d17 100644
--- a/paso/src/SystemMatrixPattern.cpp
+++ b/paso/src/SystemMatrixPattern.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrixPattern.h b/paso/src/SystemMatrixPattern.h
index d8f56dc..0901a56 100644
--- a/paso/src/SystemMatrixPattern.h
+++ b/paso/src/SystemMatrixPattern.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrixPattern_unrollBlocks.cpp b/paso/src/SystemMatrixPattern_unrollBlocks.cpp
index a01194d..7810558 100644
--- a/paso/src/SystemMatrixPattern_unrollBlocks.cpp
+++ b/paso/src/SystemMatrixPattern_unrollBlocks.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix_MatrixVector.cpp b/paso/src/SystemMatrix_MatrixVector.cpp
index 0d88972..79d272b 100644
--- a/paso/src/SystemMatrix_MatrixVector.cpp
+++ b/paso/src/SystemMatrix_MatrixVector.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix_copyRemoteCoupleBlock.cpp b/paso/src/SystemMatrix_copyRemoteCoupleBlock.cpp
index b0c93fe..6891f35 100644
--- a/paso/src/SystemMatrix_copyRemoteCoupleBlock.cpp
+++ b/paso/src/SystemMatrix_copyRemoteCoupleBlock.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix_debug.cpp b/paso/src/SystemMatrix_debug.cpp
index c23e6bc..f42a17a 100644
--- a/paso/src/SystemMatrix_debug.cpp
+++ b/paso/src/SystemMatrix_debug.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix_extendedRows.cpp b/paso/src/SystemMatrix_extendedRows.cpp
index 76d57a4..8c829e8 100644
--- a/paso/src/SystemMatrix_extendedRows.cpp
+++ b/paso/src/SystemMatrix_extendedRows.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix_loadMM.cpp b/paso/src/SystemMatrix_loadMM.cpp
index 3aad76b..ae0b4be 100644
--- a/paso/src/SystemMatrix_loadMM.cpp
+++ b/paso/src/SystemMatrix_loadMM.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/SystemMatrix_mergeMainAndCouple.cpp b/paso/src/SystemMatrix_mergeMainAndCouple.cpp
index 00dfeb6..09515d1 100644
--- a/paso/src/SystemMatrix_mergeMainAndCouple.cpp
+++ b/paso/src/SystemMatrix_mergeMainAndCouple.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/TFQMR.cpp b/paso/src/TFQMR.cpp
index f7d3798..f251998 100644
--- a/paso/src/TFQMR.cpp
+++ b/paso/src/TFQMR.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Transport.cpp b/paso/src/Transport.cpp
index eeb9c8d..0f4671d 100644
--- a/paso/src/Transport.cpp
+++ b/paso/src/Transport.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Transport.h b/paso/src/Transport.h
index 91d5650..7ebc469 100644
--- a/paso/src/Transport.h
+++ b/paso/src/Transport.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/Transport_solve.cpp b/paso/src/Transport_solve.cpp
index af2efcd..8845933 100644
--- a/paso/src/Transport_solve.cpp
+++ b/paso/src/Transport_solve.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/UMFPACK.cpp b/paso/src/UMFPACK.cpp
index b1b1345..5d3037c 100644
--- a/paso/src/UMFPACK.cpp
+++ b/paso/src/UMFPACK.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/UMFPACK.h b/paso/src/UMFPACK.h
index cace4ac..e2e5127 100644
--- a/paso/src/UMFPACK.h
+++ b/paso/src/UMFPACK.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/mmio.cpp b/paso/src/mmio.cpp
index 4ef760d..390e8c6 100644
--- a/paso/src/mmio.cpp
+++ b/paso/src/mmio.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/mmio.h b/paso/src/mmio.h
index aed1990..bef8fe8 100644
--- a/paso/src/mmio.h
+++ b/paso/src/mmio.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/performance.cpp b/paso/src/performance.cpp
index d272e72..3b451ef 100644
--- a/paso/src/performance.cpp
+++ b/paso/src/performance.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/performance.h b/paso/src/performance.h
index 52c4026..f7c420e 100644
--- a/paso/src/performance.h
+++ b/paso/src/performance.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/paso/src/solve.cpp b/paso/src/solve.cpp
index 18a630a..827a2b0 100644
--- a/paso/src/solve.cpp
+++ b/paso/src/solve.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pasowrap/py_src/SConscript b/pasowrap/py_src/SConscript
index 3cc56a8..3b14d6f 100644
--- a/pasowrap/py_src/SConscript
+++ b/pasowrap/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/pasowrap/py_src/__init__.py b/pasowrap/py_src/__init__.py
index 1bc0462..01e7b78 100644
--- a/pasowrap/py_src/__init__.py
+++ b/pasowrap/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pasowrap/py_src/pasowrap.py b/pasowrap/py_src/pasowrap.py
index 2f11ea5..1c835ab 100644
--- a/pasowrap/py_src/pasowrap.py
+++ b/pasowrap/py_src/pasowrap.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2011-2014 by University of Queensland
+# Copyright (c) 2011-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2011-2014 by University of Queensland
+__copyright__="""Copyright (c) 2011-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pasowrap/src/PasoException.cpp b/pasowrap/src/PasoException.cpp
index 3052805..b472ea4 100644
--- a/pasowrap/src/PasoException.cpp
+++ b/pasowrap/src/PasoException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pasowrap/src/PasoException.h b/pasowrap/src/PasoException.h
index bf02a50..ca44941 100644
--- a/pasowrap/src/PasoException.h
+++ b/pasowrap/src/PasoException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pasowrap/src/SConscript b/pasowrap/src/SConscript
index 50cf6a4..9561eda 100644
--- a/pasowrap/src/SConscript
+++ b/pasowrap/src/SConscript
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/pasowrap/src/SystemMatrixAdapter.cpp b/pasowrap/src/SystemMatrixAdapter.cpp
index f58cb1f..02f7ec6 100644
--- a/pasowrap/src/SystemMatrixAdapter.cpp
+++ b/pasowrap/src/SystemMatrixAdapter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "SystemMatrixAdapter.h" 
 #include <escript/SolverOptions.h>
 #include <paso/Solver.h>
diff --git a/pasowrap/src/SystemMatrixAdapter.h b/pasowrap/src/SystemMatrixAdapter.h
index ae01a99..d21a2f5 100644
--- a/pasowrap/src/SystemMatrixAdapter.h
+++ b/pasowrap/src/SystemMatrixAdapter.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pasowrap/src/TransportProblemAdapter.cpp b/pasowrap/src/TransportProblemAdapter.cpp
index 843f514..c80dbf5 100644
--- a/pasowrap/src/TransportProblemAdapter.cpp
+++ b/pasowrap/src/TransportProblemAdapter.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include "TransportProblemAdapter.h" 
 #include "SystemMatrixAdapter.h" 
 
diff --git a/pasowrap/src/TransportProblemAdapter.h b/pasowrap/src/TransportProblemAdapter.h
index 4499f53..a50aa95 100644
--- a/pasowrap/src/TransportProblemAdapter.h
+++ b/pasowrap/src/TransportProblemAdapter.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pasowrap/src/pasowrapcpp.cpp b/pasowrap/src/pasowrapcpp.cpp
index 756f06e..56d954f 100644
--- a/pasowrap/src/pasowrapcpp.cpp
+++ b/pasowrap/src/pasowrapcpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,8 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 
 
 #include <paso/Paso.h>
diff --git a/pasowrap/src/system_dep.h b/pasowrap/src/system_dep.h
index ad2bf87..b538270 100644
--- a/pasowrap/src/system_dep.h
+++ b/pasowrap/src/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -26,20 +26,7 @@
 #ifndef pasowrap_system_dep_h
 #define pasowrap_system_dep_h
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/*
- * The Intel compiler on windows has an "improved" math library compared to
- * the usual Visual C++ one. In particular it has acosh and other similar
- * functions which aren't implemented in Visual C++ math.h.
- * Note you will get a compile time error if any other header (including
- * system ones) includes math.h whilst mathimf.h has been included.
- * As a result system_dep.h must be included FIRST at all times (this
- * prevents math.h from being included).
- */
-#   include <mathimf.h>
-#else
-#   include <cmath>
-#endif
+#include <cmath>
 
 #define PASOWRAP_DLL_API
 
diff --git a/pycad/py_src/SConscript b/pycad/py_src/SConscript
index 0d35366..08a14f4 100644
--- a/pycad/py_src/SConscript
+++ b/pycad/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/pycad/py_src/Triangle.py b/pycad/py_src/Triangle.py
index 0f87ccc..caf686f 100644
--- a/pycad/py_src/Triangle.py
+++ b/pycad/py_src/Triangle.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/__init__.py b/pycad/py_src/__init__.py
index 321b184..4005d40 100644
--- a/pycad/py_src/__init__.py
+++ b/pycad/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/design.py b/pycad/py_src/design.py
index 405dd19..aa89bd7 100644
--- a/pycad/py_src/design.py
+++ b/pycad/py_src/design.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,9 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+from __future__ import print_function
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/extras.py b/pycad/py_src/extras.py
index acbfb36..560bd28 100644
--- a/pycad/py_src/extras.py
+++ b/pycad/py_src/extras.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/gmsh.py b/pycad/py_src/gmsh.py
index 1efbf6f..264c45a 100644
--- a/pycad/py_src/gmsh.py
+++ b/pycad/py_src/gmsh.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/primitives.py b/pycad/py_src/primitives.py
index 5c52162..ebb29c7 100644
--- a/pycad/py_src/primitives.py
+++ b/pycad/py_src/primitives.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/shapes.py b/pycad/py_src/shapes.py
index 3d815a1..b16453f 100644
--- a/pycad/py_src/shapes.py
+++ b/pycad/py_src/shapes.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/py_src/transformations.py b/pycad/py_src/transformations.py
index 3d076d8..a7747a1 100644
--- a/pycad/py_src/transformations.py
+++ b/pycad/py_src/transformations.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pycad/test/python/SConscript b/pycad/test/python/SConscript
index ebadbc0..871dda0 100644
--- a/pycad/test/python/SConscript
+++ b/pycad/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -29,9 +29,9 @@ localtestruns = [x for x in Glob('*.py', strings=True) if not x.startswith('run_
 alltestruns = testruns + localtestruns
 
 # test files are just compiled - none of those in pycad yet
-#sources = Glob('test_*.py')
-#test_pyc = env.PyCompile(sources)
-#env.Alias('build_py_tests', test_pyc)
+sources = Glob('run_*.py')
+test_pyc = env.PyCompile(sources)
+env.Alias('build_py_tests', test_pyc)
 
 # add unit test to target alias
 local_env.PrependENVPath('PYTHONPATH', Dir('#/pycad/test/python'))
@@ -44,6 +44,8 @@ env.Alias('py_tests', [splitext(x)[0]+'.passed' for x in testruns])
 # run all tests
 program = local_env.RunPyUnitTest(alltestruns)
 Depends(program, 'build_py_tests')
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # add a group of tests
 from grouptest import *
diff --git a/pycad/test/python/run_pycad_test.py b/pycad/test/python/run_pycad_test.py
index b67b532..796cbe5 100644
--- a/pycad/test/python/run_pycad_test.py
+++ b/pycad/test/python/run_pycad_test.py
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/pythonMPI/src/SConscript b/pythonMPI/src/SConscript
index 4e5e5e8..4d6b80b 100644
--- a/pythonMPI/src/SConscript
+++ b/pythonMPI/src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/pythonMPI/src/ScriptMPI.cpp b/pythonMPI/src/ScriptMPI.cpp
index 46b3cb5..a8e53aa 100644
--- a/pythonMPI/src/ScriptMPI.cpp
+++ b/pythonMPI/src/ScriptMPI.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pythonMPI/src/ScriptMPIredirect.cpp b/pythonMPI/src/ScriptMPIredirect.cpp
index 142b7b5..af18496 100644
--- a/pythonMPI/src/ScriptMPIredirect.cpp
+++ b/pythonMPI/src/ScriptMPIredirect.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/py_src/MultiResolutionDomain.py b/ripley/py_src/MultiResolutionDomain.py
new file mode 100644
index 0000000..848cc26
--- /dev/null
+++ b/ripley/py_src/MultiResolutionDomain.py
@@ -0,0 +1,96 @@
+
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+from __future__ import division, print_function
+
+from esys.ripley import MultiRectangle, MultiBrick
+
+class MultiResolutionDomain(object):
+    """ Constructs domains of varying resolutions that are guaranteed to be
+    compatible for cross-domain interpolation. The parameters supplied will be
+    used to construct the coarsest resolution. No coarser domain can be
+    constructed.
+    
+    Each domain of finer resolution will have the number of elements in every
+    axis of the coarsest domain multiplied by ``2**n``, where ``n`` is the level of
+    subdivision.
+    """
+    def __init__(self, dim, **kwargs):
+        """
+        :param dim: the spatial dimension of the domain to create
+        :type dim: `int`
+        :param kwargs: the arguments normally passed to a constructor of
+                Rectangle or Brick, including as the number of elements ``n0=...``, ``n1=...``, etc.
+        """
+        self.__kwargs = kwargs
+        self.__levels = {}
+        self.__dim = dim
+        self.__generateDomain(0)
+
+    def __generateDomain(self, level):
+        if self.__dim == 2:
+            self.__levels[level] = self.__newRectangle(2**level)
+        elif self.__dim == 3:
+            self.__levels[level] = self.__newBrick(2**level)
+        else:
+            raise ValueError("Invalid spatial dimension of domain: %d"%self.__dim)
+        return self.__levels[level]
+    
+    def __newRectangle(self, subdivisions):
+        n0 = self.__kwargs['n0']
+        n1 = self.__kwargs['n1']
+        l0 = self.__kwargs.get('l0', 1.)
+        l1 = self.__kwargs.get('l1', 1.)
+        d0 = self.__kwargs.get('d0', -1)
+        d1 = self.__kwargs.get('d1', -1)
+        diracPoints = self.__kwargs.get('diracPoints', [])
+        tags = self.__kwargs.get('diracTags', [])
+        escriptworld = self.__kwargs.get('escriptWorld', None)
+        return MultiRectangle(n0, n1, l0, l1, d0, d1, diracPoints, tags,
+                escriptworld, subdivisions)
+
+    def __newBrick(self, subdivisions):
+        n0 = self.__kwargs['n0']
+        n1 = self.__kwargs['n1']
+        n2 = self.__kwargs['n2']
+        l0 = self.__kwargs.get('l0', 1.)
+        l1 = self.__kwargs.get('l1', 1.)
+        l2 = self.__kwargs.get('l2', 1.)
+        d0 = self.__kwargs.get('d0', -1)
+        d1 = self.__kwargs.get('d1', -1)
+        d2 = self.__kwargs.get('d2', -1)
+        diracPoints = self.__kwargs.get('diracPoints', [])
+        tags = self.__kwargs.get('diracTags', [])
+        escriptworld = self.__kwargs.get('escriptWorld', None)
+        return MultiBrick(n0, n1, n2, l0, l1, l2, d0, d1, d2, diracPoints, tags,
+                escriptworld, subdivisions)
+
+    def getMaxDepth(self):
+        """ Returns the level of the finest domain created so far """
+        return len(self.__levels) - 1
+    
+    def getLevel(self, level):
+        """ Returns a domain with each element subdivided ``level`` times 
+        
+        :param level: the number of times to subdivide each element
+        :type level: `int`
+        """
+        if int(level) != level or level < 0:
+            raise ValueError("level must be a non-negative integer")
+        dom = self.__levels.get(level)
+        if not dom:
+            dom = self.__generateDomain(level)
+        return dom
diff --git a/ripley/py_src/SConscript b/ripley/py_src/SConscript
index 6f247ef..6dbd59b 100644
--- a/ripley/py_src/SConscript
+++ b/ripley/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/ripley/py_src/__init__.py b/ripley/py_src/__init__.py
index 3bd5e02..17e169e 100644
--- a/ripley/py_src/__init__.py
+++ b/ripley/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@
 """A domain meshed with uniform rectangles or quadrilaterals
 """
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -26,6 +26,6 @@ __url__="https://launchpad.net/escript-finley"
 
 import esys.escript		# This is just to ensure required libraries are loaded
 from .ripleycpp import *
-
+from .MultiResolutionDomain import *
 
 __nodocorecursion=['ripleycpp']
\ No newline at end of file
diff --git a/ripley/src/AbstractAssembler.h b/ripley/src/AbstractAssembler.h
index bd721ff..f07e8b8 100644
--- a/ripley/src/AbstractAssembler.h
+++ b/ripley/src/AbstractAssembler.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/Brick.cpp b/ripley/src/Brick.cpp
index 19f4e8f..fba3904 100644
--- a/ripley/src/Brick.cpp
+++ b/ripley/src/Brick.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,17 +14,19 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include <esysUtils/first.h>
+#include <esysUtils/esysFileWriter.h>
+#include <esysUtils/EsysRandom.h>
+
+#include <paso/SystemMatrix.h>
+
 #include <ripley/Brick.h>
 #include <ripley/DefaultAssembler3D.h>
 #include <ripley/LameAssembler3D.h>
 #include <ripley/WaveAssembler3D.h>
 #include <ripley/blocktools.h>
 #include <ripley/domainhelpers.h>
-#include <esysUtils/esysFileWriter.h>
-#include <esysUtils/EsysRandom.h>
-#include <paso/SystemMatrix.h>
-
-#include <boost/scoped_array.hpp>
 
 #ifdef USE_NETCDF
 #include <netcdfcpp.h>
@@ -37,13 +39,22 @@
 #endif
 #endif
 
+#include <boost/math/special_functions/fpclassify.hpp>	// for isnan
+#include <boost/scoped_array.hpp>
+
 #include <iomanip>
 #include <limits>
 
 namespace bp = boost::python;
-using namespace std;
+namespace bm = boost::math;
 using esysUtils::FileWriter;
 using escript::AbstractSystemMatrix;
+using std::vector;
+using std::string;
+using std::min;
+using std::max;
+using std::ios;
+using std::fill;
 
 namespace ripley {
 
@@ -68,7 +79,7 @@ Brick::Brick(dim_t n0, dim_t n1, dim_t n2, double x0, double y0, double z0,
     RipleyDomain(3, w)
 {
     if (static_cast<long>(n0 + 1) * static_cast<long>(n1 + 1)
-            * static_cast<long>(n2 + 1) > numeric_limits<dim_t>::max())
+            * static_cast<long>(n2 + 1) > std::numeric_limits<dim_t>::max())
         throw RipleyException("The number of elements has overflowed, this "
                 "limit may be raised in future releases.");
 
@@ -121,8 +132,8 @@ Brick::Brick(dim_t n0, dim_t n1, dim_t n2, double x0, double y0, double z0,
         throw RipleyException("Invalid number of spatial subdivisions");
     }
     if (warn) {
-        cout << "Warning: Automatic domain subdivision (d0=" << d0 << ", d1="
-            << d1 << ", d2=" << d2 << "). This may not be optimal!" << endl;
+        std::cout << "Warning: Automatic domain subdivision (d0=" << d0 << ", d1="
+            << d1 << ", d2=" << d2 << "). This may not be optimal!" << std::endl;
     }
 
     double l0 = x1-x0;
@@ -135,20 +146,20 @@ Brick::Brick(dim_t n0, dim_t n1, dim_t n2, double x0, double y0, double z0,
     if ((n0+1)%d0 > 0) {
         n0=(dim_t)round((float)(n0+1)/d0+0.5)*d0-1;
         l0=m_dx[0]*n0;
-        cout << "Warning: Adjusted number of elements and length. N0="
-            << n0 << ", l0=" << l0 << endl;
+        std::cout << "Warning: Adjusted number of elements and length. N0="
+            << n0 << ", l0=" << l0 << std::endl;
     }
     if ((n1+1)%d1 > 0) {
         n1=(dim_t)round((float)(n1+1)/d1+0.5)*d1-1;
         l1=m_dx[1]*n1;
-        cout << "Warning: Adjusted number of elements and length. N1="
-            << n1 << ", l1=" << l1 << endl;
+        std::cout << "Warning: Adjusted number of elements and length. N1="
+            << n1 << ", l1=" << l1 << std::endl;
     }
     if ((n2+1)%d2 > 0) {
         n2=(dim_t)round((float)(n2+1)/d2+0.5)*d2-1;
         l2=m_dx[2]*n2;
-        cout << "Warning: Adjusted number of elements and length. N2="
-            << n2 << ", l2=" << l2 << endl;
+        std::cout << "Warning: Adjusted number of elements and length. N2="
+            << n2 << ", l2=" << l2 << std::endl;
     }
 
     if ((d0 > 1 && (n0+1)/d0<2) || (d1 > 1 && (n1+1)/d1<2) || (d2 > 1 && (n2+1)/d2<2))
@@ -358,7 +369,7 @@ void Brick::readNcGrid(escript::Data& out, string filename, string varname,
                 const dim_t srcIndex=(z0+z_mult*z)*num1*num0
                                   +(y0+y_mult*y)*num0
                                   +(x0+x_mult*x);
-                if (!isnan(values[srcIndex])) {
+                if (!bm::isnan(values[srcIndex])) {
                     for (index_t m2=0; m2<params.multiplier[2]; m2++) {
                         for (index_t m1=0; m1<params.multiplier[1]; m1++) {
                             for (index_t m0=0; m0<params.multiplier[0]; m0++) {
@@ -456,11 +467,11 @@ void Brick::readBinaryGridImpl(escript::Data& out, const string& filename,
         throw RipleyException("readBinaryGrid(): reversing only supported in Z-direction currently");
 
     // check file existence and size
-    ifstream f(filename.c_str(), ifstream::binary);
+    std::ifstream f(filename.c_str(), std::ifstream::binary);
     if (f.fail()) {
         throw RipleyException("readBinaryGrid(): cannot open file");
     }
-    f.seekg(0, ios::end);
+    f.seekg(0, std::ios::end);
     const int numComp = out.getDataPointSize();
     const dim_t filesize = f.tellg();
     const dim_t reqsize = params.numValues[0]*params.numValues[1]*params.numValues[2]*numComp*sizeof(ValueType);
@@ -563,7 +574,7 @@ void Brick::readBinaryGridImpl(escript::Data& out, const string& filename,
                                         byte_swap32(cval);
                                     }
                                 }
-                                if (!isnan(val)) {
+                                if (!bm::isnan(val)) {
                                     for (int q=0; q<dpp; q++) {
                                         *dest++ = static_cast<double>(val);
                                     }
@@ -611,11 +622,11 @@ void Brick::readBinaryGridZippedImpl(escript::Data& out, const string& filename,
             throw RipleyException("readBinaryGridFromZipped(): all multipliers must be positive");
 
     // check file existence and size
-    ifstream f(filename.c_str(), ifstream::binary);
+    std::ifstream f(filename.c_str(), std::ifstream::binary);
     if (f.fail()) {
         throw RipleyException("readBinaryGridFromZipped(): cannot open file");
     }
-    f.seekg(0, ios::end);
+    f.seekg(0, std::ios::end);
     const int numComp = out.getDataPointSize();
     dim_t filesize = f.tellg();
     f.seekg(0, ios::beg);
@@ -683,7 +694,7 @@ void Brick::readBinaryGridZippedImpl(escript::Data& out, const string& filename,
                                     // this will alter val!!
                                     byte_swap32(cval);
                                 }
-                                if (!isnan(val)) {
+                                if (!bm::isnan(val)) {
                                     for (int q=0; q<dpp; q++) {
                                         *dest++ = static_cast<double>(val);
                                     }
@@ -777,7 +788,7 @@ void Brick::writeBinaryGridImpl(const escript::Data& in,
         for (index_t y=0; y<myN1; y++) {
             const dim_t fileofs = (offset0+(offset1+y)*totalN0
                                 +(offset2+z)*totalN0*totalN1)*sizeof(ValueType);
-            ostringstream oss;
+            std::ostringstream oss;
 
             for (index_t x=0; x<myN0; x++) {
                 const double* sample = in.getSampleDataRO(z*myN0*myN1+y*myN0+x);
@@ -909,8 +920,8 @@ void Brick::dump(const string& fileName) const
         vector<string> tempstrings;
         vector<char*> names;
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/mesh";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/mesh";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -921,8 +932,8 @@ void Brick::dump(const string& fileName) const
         tempstrings.clear();
         names.clear();
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/nodeId";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/nodeId";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -932,8 +943,8 @@ void Brick::dump(const string& fileName) const
         tempstrings.clear();
         names.clear();
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/elementId";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/elementId";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -976,7 +987,7 @@ const dim_t* Brick::borrowSampleReferenceIDs(int fsType) const
             break;
     }
 
-    stringstream msg;
+    std::stringstream msg;
     msg << "borrowSampleReferenceIDs: invalid function space type "<<fsType;
     throw RipleyException(msg.str());
 }
@@ -1029,11 +1040,121 @@ bool Brick::ownSample(int fsType, index_t id) const
             break;
     }
 
-    stringstream msg;
+    std::stringstream msg;
     msg << "ownSample: invalid function space type " << fsType;
     throw RipleyException(msg.str());
 }
 
+RankVector Brick::getOwnerVector(int fsType) const
+{
+    RankVector owner;
+    const Esys_MPI_rank rank = m_mpiInfo->rank;
+
+    if (fsType == Elements || fsType == ReducedElements) {
+        owner.assign(getNumElements(), rank);
+        // shared plane in Y-Z
+        if (m_faceCount[0]==0) {
+            for (dim_t k2=0; k2<m_NE[2]; k2++) {
+                for (dim_t k1=0; k1<m_NE[1]; k1++) {
+                    const dim_t e=k2*m_NE[0]*m_NE[1]+k1*m_NE[0];
+                    owner[e] = rank-1;
+                }
+            }
+        }
+        // shared plane in X-Z
+        if (m_faceCount[2]==0) {
+            for (dim_t k2=0; k2<m_NE[2]; k2++) {
+                for (dim_t k0=0; k0<m_NE[0]; k0++) {
+                    const dim_t e=k2*m_NE[0]*m_NE[1]+k0;
+                    owner[e] = rank-m_NX[0];
+                }
+            }
+        }
+        // shared plane in X-Y
+        if (m_faceCount[4]==0) {
+            for (dim_t k1=0; k1<m_NE[1]; k1++) {
+                for (dim_t k0=0; k0<m_NE[0]; k0++) {
+                    const dim_t e=k1*m_NE[0]+k0;
+                    owner[e] = rank-m_NX[0]*m_NX[1];
+                }
+            }
+        }
+
+    } else if (fsType == FaceElements || fsType == ReducedFaceElements) {
+        owner.assign(getNumFaceElements(), rank);
+        index_t offset=0;
+        if (m_faceCount[0] > 0) {
+            if (m_faceCount[2]==0) {
+                for (dim_t k2=0; k2<m_NE[2]; k2++)
+                    owner[k2*m_NE[1]] = rank-m_NX[0];
+            }
+            if (m_faceCount[4]==0) {
+                for (dim_t k1=0; k1<m_NE[1]; k1++)
+                    owner[k1] = rank-m_NX[0]*m_NX[1];
+            }
+            offset += m_faceCount[0];
+        }
+        if (m_faceCount[1] > 0) {
+            if (m_faceCount[2]==0) {
+                for (dim_t k2=0; k2<m_NE[2]; k2++)
+                    owner[offset+k2*m_NE[1]] = rank-m_NX[0];
+            }
+            if (m_faceCount[4]==0) {
+                for (dim_t k1=0; k1<m_NE[1]; k1++)
+                    owner[offset+k1] = rank-m_NX[0]*m_NX[1];
+            }
+            offset += m_faceCount[1];
+        }
+        if (m_faceCount[2] > 0) {
+            if (m_faceCount[0]==0) {
+                for (dim_t k2=0; k2<m_NE[2]; k2++)
+                    owner[offset+k2*m_NE[0]] = rank-1;
+            }
+            if (m_faceCount[4]==0) {
+                for (dim_t k0=0; k0<m_NE[0]; k0++)
+                    owner[offset+k0] = rank-m_NX[0]*m_NX[1];
+            }
+            offset += m_faceCount[2];
+        }
+        if (m_faceCount[3] > 0) {
+            if (m_faceCount[0]==0) {
+                for (dim_t k2=0; k2<m_NE[2]; k2++)
+                    owner[offset+k2*m_NE[0]] = rank-1;
+            }
+            if (m_faceCount[4]==0) {
+                for (dim_t k0=0; k0<m_NE[0]; k0++)
+                    owner[offset+k0] = rank-m_NX[0]*m_NX[1];
+            }
+            offset += m_faceCount[3];
+        }
+        if (m_faceCount[4] > 0) {
+            if (m_faceCount[0]==0) {
+                for (dim_t k1=0; k1<m_NE[1]; k1++)
+                    owner[offset+k1*m_NE[0]] = rank-1;
+            }
+            if (m_faceCount[2]==0) {
+                for (dim_t k0=0; k0<m_NE[0]; k0++)
+                    owner[offset+k0] = rank-m_NX[0];
+            }
+            offset += m_faceCount[4];
+        }
+        if (m_faceCount[5] > 0) {
+            if (m_faceCount[0]==0) {
+                for (dim_t k1=0; k1<m_NE[1]; k1++)
+                    owner[offset+k1*m_NE[0]] = rank-1;
+            }
+            if (m_faceCount[2]==0) {
+                for (dim_t k0=0; k0<m_NE[0]; k0++)
+                    owner[offset+k0] = rank-m_NX[0];
+            }
+        }
+    } else {
+        throw RipleyException("getOwnerVector: only valid for element types");
+    }
+
+    return owner;
+}
+
 void Brick::setToNormal(escript::Data& out) const
 {
     const dim_t NE0 = m_NE[0];
@@ -1206,7 +1327,7 @@ void Brick::setToNormal(escript::Data& out) const
         } // end of parallel section
 
     } else {
-        stringstream msg;
+        std::stringstream msg;
         msg << "setToNormal: invalid function space type "
             << out.getFunctionSpace().getTypeCode();
         throw RipleyException(msg.str());
@@ -1303,7 +1424,7 @@ void Brick::setToSize(escript::Data& out) const
         } // end of parallel section
 
     } else {
-        stringstream msg;
+        std::stringstream msg;
         msg << "setToSize: invalid function space type "
             << out.getFunctionSpace().getTypeCode();
         throw RipleyException(msg.str());
@@ -1314,14 +1435,14 @@ void Brick::Print_Mesh_Info(const bool full) const
 {
     RipleyDomain::Print_Mesh_Info(full);
     if (full) {
-        cout << "     Id  Coordinates" << endl;
-        cout.precision(15);
-        cout.setf(ios::scientific, ios::floatfield);
+        std::cout << "     Id  Coordinates" << std::endl;
+        std::cout.precision(15);
+        std::cout.setf(ios::scientific, std::ios::floatfield);
         for (index_t i=0; i < getNumNodes(); i++) {
-            cout << "  " << setw(5) << m_nodeId[i]
+            std::cout << "  " << std::setw(5) << m_nodeId[i]
                 << "  " << getLocalCoordinate(i%m_NN[0], 0)
                 << "  " << getLocalCoordinate(i%(m_NN[0]*m_NN[1])/m_NN[0], 1)
-                << "  " << getLocalCoordinate(i/(m_NN[0]*m_NN[1]), 2) << endl;
+                << "  " << getLocalCoordinate(i/(m_NN[0]*m_NN[1]), 2) << std::endl;
         }
     }
 }
@@ -1330,11 +1451,10 @@ void Brick::Print_Mesh_Info(const bool full) const
 //protected
 void Brick::assembleCoordinates(escript::Data& arg) const
 {
-    escriptDataC x = arg.getDataC();
     int numDim = m_numDim;
-    if (!isDataPointShapeEqual(&x, 1, &numDim))
+    if (&arg!=0 && !arg.isDataPointShapeEqual(1, &numDim))
         throw RipleyException("setToX: Invalid Data object shape");
-    if (!numSamplesEqual(&x, 1, getNumNodes()))
+    if (&arg!=0 && !arg.numSamplesEqual(1, getNumNodes()))
         throw RipleyException("setToX: Illegal number of samples in Data object");
 
     const dim_t NN0 = m_NN[0];
@@ -2126,7 +2246,7 @@ void Brick::nodesToDOF(escript::Data& out, const escript::Data& in) const
             for (index_t k=0; k<nDOF0; k++) {
                 const index_t n=k+left+(j+bottom)*m_NN[0]+(i+front)*m_NN[0]*m_NN[1];
                 const double* src=in.getSampleDataRO(n);
-                copy(src, src+numComp, out.getSampleDataRW(k+j*nDOF0+i*nDOF0*nDOF1));
+                std::copy(src, src+numComp, out.getSampleDataRW(k+j*nDOF0+i*nDOF0*nDOF1));
             }
         }
     }
@@ -2151,7 +2271,7 @@ void Brick::dofToNodes(escript::Data& out, const escript::Data& in) const
         const double* src=(m_dofMap[i]<numDOF ?
                 in.getSampleDataRO(m_dofMap[i])
                 : &buffer[(m_dofMap[i]-numDOF)*numComp]);
-        copy(src, src+numComp, out.getSampleDataRW(i));
+        std::copy(src, src+numComp, out.getSampleDataRW(i));
     }
 }
 
@@ -2315,43 +2435,43 @@ paso::SystemMatrixPattern_ptr Brick::getPasoMatrixPattern(
 
     // useful debug output
     /*
-    cout << "--- colIndices ---" << endl;
+    std::cout << "--- colIndices ---" << std::endl;
     for (size_t i=0; i<colIndices.size(); i++) {
-        cout << "colIndices[" << i << "].size()=" << colIndices[i].size() << endl;
+        std::cout << "colIndices[" << i << "].size()=" << colIndices[i].size() << std::endl;
     }
-    cout << "--- rowIndices ---" << endl;
+    std::cout << "--- rowIndices ---" << std::endl;
     for (size_t i=0; i<rowIndices.size(); i++) {
-        cout << "rowIndices[" << i << "].size()=" << rowIndices[i].size() << endl;
+        std::cout << "rowIndices[" << i << "].size()=" << rowIndices[i].size() << std::endl;
     }
     */
     /*
-    cout << "--- main_pattern ---" << endl;
-    cout << "M=" << mainPattern->numOutput << ", N=" << mainPattern->numInput << endl;
+    std::cout << "--- main_pattern ---" << std::endl;
+    std::cout << "M=" << mainPattern->numOutput << ", N=" << mainPattern->numInput << std::endl;
     for (size_t i=0; i<mainPattern->numOutput+1; i++) {
-        cout << "ptr[" << i << "]=" << mainPattern->ptr[i] << endl;
+        std::cout << "ptr[" << i << "]=" << mainPattern->ptr[i] << std::endl;
     }
     for (size_t i=0; i<mainPattern->ptr[mainPattern->numOutput]; i++) {
-        cout << "index[" << i << "]=" << mainPattern->index[i] << endl;
+        std::cout << "index[" << i << "]=" << mainPattern->index[i] << std::endl;
     }
     */
     /*
-    cout << "--- colCouple_pattern ---" << endl;
-    cout << "M=" << colPattern->numOutput << ", N=" << colPattern->numInput << endl;
+    std::cout << "--- colCouple_pattern ---" << std::endl;
+    std::cout << "M=" << colPattern->numOutput << ", N=" << colPattern->numInput << std::endl;
     for (size_t i=0; i<colPattern->numOutput+1; i++) {
-        cout << "ptr[" << i << "]=" << colPattern->ptr[i] << endl;
+        std::cout << "ptr[" << i << "]=" << colPattern->ptr[i] << std::endl;
     }
     for (size_t i=0; i<colPattern->ptr[colPattern->numOutput]; i++) {
-        cout << "index[" << i << "]=" << colPattern->index[i] << endl;
+        std::cout << "index[" << i << "]=" << colPattern->index[i] << std::endl;
     }
     */
     /*
-    cout << "--- rowCouple_pattern ---" << endl;
-    cout << "M=" << rowPattern->numOutput << ", N=" << rowPattern->numInput << endl;
+    std::cout << "--- rowCouple_pattern ---" << std::endl;
+    std::cout << "M=" << rowPattern->numOutput << ", N=" << rowPattern->numInput << std::endl;
     for (size_t i=0; i<rowPattern->numOutput+1; i++) {
-        cout << "ptr[" << i << "]=" << rowPattern->ptr[i] << endl;
+        std::cout << "ptr[" << i << "]=" << rowPattern->ptr[i] << std::endl;
     }
     for (size_t i=0; i<rowPattern->ptr[rowPattern->numOutput]; i++) {
-        cout << "index[" << i << "]=" << rowPattern->index[i] << endl;
+        std::cout << "index[" << i << "]=" << rowPattern->index[i] << std::endl;
     }
     */
 
@@ -2381,7 +2501,7 @@ void Brick::populateSampleIds()
         m_nodeId.resize(getNumNodes());
         m_dofId.resize(numDOF);
         m_elementId.resize(getNumElements());
-    } catch (const length_error& le) {
+    } catch (const std::length_error& le) {
         throw RipleyException("The system does not have sufficient memory for a domain of this size.");
     }
 
@@ -2806,22 +2926,22 @@ void Brick::populateDofMap()
 
     // useful debug output
     /*
-    cout << "--- rcv_shcomp ---" << endl;
-    cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << endl;
+    std::cout << "--- rcv_shcomp ---" << std::endl;
+    std::cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << std::endl;
     for (size_t i=0; i<neighbour.size(); i++) {
-        cout << "neighbor[" << i << "]=" << neighbour[i]
-            << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << endl;
+        std::cout << "neighbor[" << i << "]=" << neighbour[i]
+            << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << std::endl;
     }
     for (size_t i=0; i<recvShared.size(); i++) {
-        cout << "shared[" << i << "]=" << recvShared[i] << endl;
+        std::cout << "shared[" << i << "]=" << recvShared[i] << std::endl;
     }
-    cout << "--- snd_shcomp ---" << endl;
+    std::cout << "--- snd_shcomp ---" << std::endl;
     for (size_t i=0; i<sendShared.size(); i++) {
-        cout << "shared[" << i << "]=" << sendShared[i] << endl;
+        std::cout << "shared[" << i << "]=" << sendShared[i] << std::endl;
     }
-    cout << "--- dofMap ---" << endl;
+    std::cout << "--- dofMap ---" << std::endl;
     for (size_t i=0; i<m_dofMap.size(); i++) {
-        cout << "m_dofMap[" << i << "]=" << m_dofMap[i] << endl;
+        std::cout << "m_dofMap[" << i << "]=" << m_dofMap[i] << std::endl;
     }
     */
 }
@@ -3350,7 +3470,7 @@ escript::Data Brick::randomFillWorker(
     basex=X*m_gNE[0]/m_NX[0];
     basey=Y*m_gNE[1]/m_NX[1];
     basez=Z*m_gNE[2]/m_NX[2];
-cout << "basex=" << basex << " basey=" << basey << " basez=" << basez << endl;
+std::cout << "basex=" << basex << " basey=" << basey << " basez=" << basez << std::endl;
 #endif
     esysUtils::patternFillArray(1, ext[0],ext[1],ext[2], src, 4, basex, basey, basez, numvals);
 */
diff --git a/ripley/src/Brick.h b/ripley/src/Brick.h
index 8babed5..1f3c236 100644
--- a/ripley/src/Brick.h
+++ b/ripley/src/Brick.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -204,6 +204,13 @@ public:
     */
     const double *getElementLength() const { return m_dx; }
 
+    /**
+       \brief
+       returns a vector of rank numbers where vec[i]=n means that rank n
+       'owns' element/face element i.
+    */
+    virtual RankVector getOwnerVector(int fsType) const;
+
 protected:
     virtual dim_t getNumNodes() const;
     virtual dim_t getNumElements() const;
@@ -225,7 +232,6 @@ protected:
     virtual dim_t getDofOfNode(dim_t node) const;
     Assembler_ptr createAssembler(std::string type, const DataMap& constants) const;
 
-private:
     void populateSampleIds();
     void populateDofMap();
     std::vector<IndexVector> getConnections() const;
diff --git a/ripley/src/DefaultAssembler2D.cpp b/ripley/src/DefaultAssembler2D.cpp
index 2308dde..fec0fad 100644
--- a/ripley/src/DefaultAssembler2D.cpp
+++ b/ripley/src/DefaultAssembler2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,11 +14,13 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ripley/DefaultAssembler2D.h>
 #include <ripley/domainhelpers.h>
 
 using namespace std;
-
 using escript::AbstractSystemMatrix;
 using escript::Data;
 
@@ -41,6 +43,10 @@ void DefaultAssembler2D::collateFunctionSpaceTypes(vector<int>& fsTypes,
         fsTypes.push_back(coefs.find("Y")->second.getFunctionSpace().getTypeCode());
 }
 
+/****************************************************************************/
+// wrappers
+/****************************************************************************/
+
 void DefaultAssembler2D::assemblePDESingle(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
@@ -124,20 +130,17 @@ void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
     assemblePDEBoundarySystemReduced(mat, rhs, d, y);
 }
 
-void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
-                                     Data& rhs, const Data& A, const Data& B,
-                                     const Data& C, const Data& D,
-                                     const Data& X, const Data& Y) const
+/****************************************************************************/
+// PDE SINGLE
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDESingle(AbstractSystemMatrix* mat,
+                                      Data& rhs, const Data& A, const Data& B,
+                                      const Data& C, const Data& D,
+                                      const Data& X, const Data& Y) const
 {
-    dim_t numEq, numComp;
-    if (!mat)
-        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
-    else {
-        numEq=mat->getRowBlockSize();
-        numComp=mat->getColumnBlockSize();
-    }
     const double SQRT3 = 1.73205080756887719318;
-    const double w1 = 1.0/24;
+    const double w1 = 1.0/24.0;
     const double w5 = -SQRT3/24 + 1.0/12;
     const double w2 = -SQRT3/24 - 1.0/12;
     const double w19 = -m_dx[0]/12;
@@ -148,10 +151,10 @@ void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
     const double w27 = w19*(-SQRT3 - 3)/2;
     const double w28 = w19*(SQRT3 - 3)/2;
     const double w18 = -m_dx[1]/12;
-    const double w10 = w18*(SQRT3 + 3)/12;
-    const double w15 = w18*(-SQRT3 + 3)/12;
     const double w12 = w18*(5*SQRT3 + 9)/12;
     const double w13 = w18*(-5*SQRT3 + 9)/12;
+    const double w10 = w18*(SQRT3 + 3)/12;
+    const double w15 = w18*(-SQRT3 + 3)/12;
     const double w25 = w18*(-SQRT3 - 3)/2;
     const double w26 = w18*(SQRT3 - 3)/2;
     const double w22 = m_dx[0]*m_dx[1]/144;
@@ -167,467 +170,660 @@ void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
     const double w4 = w6*(-SQRT3 + 2);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
+    const bool addEM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool addEM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4, 0);
+        vector<double> EM_F(4, 0);
+
         for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
-            for (index_t k1=k1_0; k1 < NE1; k1+=2) {
-                for (index_t k0=0; k0 < NE0; ++k0)  {
-                    bool addEM_S=false;
-                    bool addEM_F=false;
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
+            for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                for (index_t k0=0; k0<NE0; ++k0)  {
                     const index_t e = k0 + NE0*k1;
+                    if (addEM_S)
+                        fill(EM_S.begin(), EM_S.end(), 0);
+                    if (addEM_F)
+                        fill(EM_F.begin(), EM_F.end(), 0);
                     ///////////////
                     // process A //
                     ///////////////
                     if (!A.isEmpty()) {
-                        addEM_S = true;
                         const double* A_p = A.getSampleDataRO(e);
                         if (A.actsExpanded()) {
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double A_00_0 = A_p[INDEX5(k,0,m,0,0,numEq,2,numComp,2)];
-                                    const double A_01_0 = A_p[INDEX5(k,0,m,1,0,numEq,2,numComp,2)];
-                                    const double A_10_0 = A_p[INDEX5(k,1,m,0,0,numEq,2,numComp,2)];
-                                    const double A_11_0 = A_p[INDEX5(k,1,m,1,0,numEq,2,numComp,2)];
-                                    const double A_00_1 = A_p[INDEX5(k,0,m,0,1,numEq,2,numComp,2)];
-                                    const double A_01_1 = A_p[INDEX5(k,0,m,1,1,numEq,2,numComp,2)];
-                                    const double A_10_1 = A_p[INDEX5(k,1,m,0,1,numEq,2,numComp,2)];
-                                    const double A_11_1 = A_p[INDEX5(k,1,m,1,1,numEq,2,numComp,2)];
-                                    const double A_00_2 = A_p[INDEX5(k,0,m,0,2,numEq,2,numComp,2)];
-                                    const double A_01_2 = A_p[INDEX5(k,0,m,1,2,numEq,2,numComp,2)];
-                                    const double A_10_2 = A_p[INDEX5(k,1,m,0,2,numEq,2,numComp,2)];
-                                    const double A_11_2 = A_p[INDEX5(k,1,m,1,2,numEq,2,numComp,2)];
-                                    const double A_00_3 = A_p[INDEX5(k,0,m,0,3,numEq,2,numComp,2)];
-                                    const double A_01_3 = A_p[INDEX5(k,0,m,1,3,numEq,2,numComp,2)];
-                                    const double A_10_3 = A_p[INDEX5(k,1,m,0,3,numEq,2,numComp,2)];
-                                    const double A_11_3 = A_p[INDEX5(k,1,m,1,3,numEq,2,numComp,2)];
-                                    const double tmp0 = w3*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
-                                    const double tmp1 = w1*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
-                                    const double tmp2 = w4*(A_00_2 + A_00_3);
-                                    const double tmp3 = w0*(A_00_0 + A_00_1);
-                                    const double tmp4 = w5*(A_01_2 - A_10_3);
-                                    const double tmp5 = w2*(-A_01_1 + A_10_0);
-                                    const double tmp6 = w5*(A_01_3 + A_10_0);
-                                    const double tmp7 = w3*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
-                                    const double tmp8 = w6*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
-                                    const double tmp9 = w1*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
-                                    const double tmp10 = w2*(-A_01_0 - A_10_3);
-                                    const double tmp11 = w4*(A_00_0 + A_00_1);
-                                    const double tmp12 = w0*(A_00_2 + A_00_3);
-                                    const double tmp13 = w5*(A_01_1 - A_10_0);
-                                    const double tmp14 = w2*(-A_01_2 + A_10_3);
-                                    const double tmp15 = w7*(A_11_0 + A_11_2);
-                                    const double tmp16 = w4*(-A_00_2 - A_00_3);
-                                    const double tmp17 = w0*(-A_00_0 - A_00_1);
-                                    const double tmp18 = w5*(A_01_3 + A_10_3);
-                                    const double tmp19 = w8*(A_11_1 + A_11_3);
-                                    const double tmp20 = w2*(-A_01_0 - A_10_0);
-                                    const double tmp21 = w7*(A_11_1 + A_11_3);
-                                    const double tmp22 = w4*(-A_00_0 - A_00_1);
-                                    const double tmp23 = w0*(-A_00_2 - A_00_3);
-                                    const double tmp24 = w5*(A_01_0 + A_10_0);
-                                    const double tmp25 = w8*(A_11_0 + A_11_2);
-                                    const double tmp26 = w2*(-A_01_3 - A_10_3);
-                                    const double tmp27 = w5*(-A_01_1 - A_10_2);
-                                    const double tmp28 = w1*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
-                                    const double tmp29 = w2*(A_01_2 + A_10_1);
-                                    const double tmp30 = w7*(-A_11_1 - A_11_3);
-                                    const double tmp31 = w1*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
-                                    const double tmp32 = w5*(-A_01_0 + A_10_2);
-                                    const double tmp33 = w8*(-A_11_0 - A_11_2);
-                                    const double tmp34 = w6*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
-                                    const double tmp35 = w2*(A_01_3 - A_10_1);
-                                    const double tmp36 = w5*(A_01_0 + A_10_3);
-                                    const double tmp37 = w2*(-A_01_3 - A_10_0);
-                                    const double tmp38 = w7*(-A_11_0 - A_11_2);
-                                    const double tmp39 = w5*(-A_01_3 + A_10_1);
-                                    const double tmp40 = w8*(-A_11_1 - A_11_3);
-                                    const double tmp41 = w2*(A_01_0 - A_10_2);
-                                    const double tmp42 = w5*(A_01_1 - A_10_3);
-                                    const double tmp43 = w2*(-A_01_2 + A_10_0);
-                                    const double tmp44 = w5*(A_01_2 - A_10_0);
-                                    const double tmp45 = w2*(-A_01_1 + A_10_3);
-                                    const double tmp46 = w5*(-A_01_0 + A_10_1);
-                                    const double tmp47 = w2*(A_01_3 - A_10_2);
-                                    const double tmp48 = w5*(-A_01_1 - A_10_1);
-                                    const double tmp49 = w2*(A_01_2 + A_10_2);
-                                    const double tmp50 = w5*(-A_01_3 + A_10_2);
-                                    const double tmp51 = w2*(A_01_0 - A_10_1);
-                                    const double tmp52 = w5*(-A_01_2 - A_10_1);
-                                    const double tmp53 = w2*(A_01_1 + A_10_2);
-                                    const double tmp54 = w5*(-A_01_2 - A_10_2);
-                                    const double tmp55 = w2*(A_01_1 + A_10_1);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp20 + tmp9;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp31 + tmp34 + tmp38 + tmp39 + tmp40 + tmp41;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp28 + tmp52 + tmp53 + tmp7 + tmp8;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0 + tmp2 + tmp3 + tmp31 + tmp50 + tmp51;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=tmp16 + tmp17 + tmp21 + tmp25 + tmp28 + tmp54 + tmp55;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp10 + tmp6 + tmp7 + tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp1 + tmp30 + tmp33 + tmp34 + tmp44 + tmp45;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp1 + tmp34 + tmp38 + tmp40 + tmp42 + tmp43;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp36 + tmp37 + tmp7 + tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=tmp15 + tmp19 + tmp22 + tmp23 + tmp28 + tmp48 + tmp49;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp0 + tmp11 + tmp12 + tmp31 + tmp46 + tmp47;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp27 + tmp28 + tmp29 + tmp7 + tmp8;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp0 + tmp1 + tmp11 + tmp12 + tmp13 + tmp14;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp9;
-                                }
-                            }
+                            const double A_00_0 = A_p[INDEX3(0,0,0,2,2)];
+                            const double A_01_0 = A_p[INDEX3(0,1,0,2,2)];
+                            const double A_10_0 = A_p[INDEX3(1,0,0,2,2)];
+                            const double A_11_0 = A_p[INDEX3(1,1,0,2,2)];
+                            const double A_00_1 = A_p[INDEX3(0,0,1,2,2)];
+                            const double A_01_1 = A_p[INDEX3(0,1,1,2,2)];
+                            const double A_10_1 = A_p[INDEX3(1,0,1,2,2)];
+                            const double A_11_1 = A_p[INDEX3(1,1,1,2,2)];
+                            const double A_00_2 = A_p[INDEX3(0,0,2,2,2)];
+                            const double A_01_2 = A_p[INDEX3(0,1,2,2,2)];
+                            const double A_10_2 = A_p[INDEX3(1,0,2,2,2)];
+                            const double A_11_2 = A_p[INDEX3(1,1,2,2,2)];
+                            const double A_00_3 = A_p[INDEX3(0,0,3,2,2)];
+                            const double A_01_3 = A_p[INDEX3(0,1,3,2,2)];
+                            const double A_10_3 = A_p[INDEX3(1,0,3,2,2)];
+                            const double A_11_3 = A_p[INDEX3(1,1,3,2,2)];
+                            const double tmp0 = w3*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
+                            const double tmp1 = w1*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
+                            const double tmp2 = w4*(A_00_2 + A_00_3);
+                            const double tmp3 = w0*(A_00_0 + A_00_1);
+                            const double tmp4 = w5*(A_01_2 - A_10_3);
+                            const double tmp5 = w2*(-A_01_1 + A_10_0);
+                            const double tmp6 = w5*(A_01_3 + A_10_0);
+                            const double tmp7 = w3*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
+                            const double tmp8 = w6*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
+                            const double tmp9 = w1*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
+                            const double tmp10 = w2*(-A_01_0 - A_10_3);
+                            const double tmp11 = w4*(A_00_0 + A_00_1);
+                            const double tmp12 = w0*(A_00_2 + A_00_3);
+                            const double tmp13 = w5*(A_01_1 - A_10_0);
+                            const double tmp14 = w2*(-A_01_2 + A_10_3);
+                            const double tmp15 = w7*(A_11_0 + A_11_2);
+                            const double tmp16 = w4*(-A_00_2 - A_00_3);
+                            const double tmp17 = w0*(-A_00_0 - A_00_1);
+                            const double tmp18 = w5*(A_01_3 + A_10_3);
+                            const double tmp19 = w8*(A_11_1 + A_11_3);
+                            const double tmp20 = w2*(-A_01_0 - A_10_0);
+                            const double tmp21 = w7*(A_11_1 + A_11_3);
+                            const double tmp22 = w4*(-A_00_0 - A_00_1);
+                            const double tmp23 = w0*(-A_00_2 - A_00_3);
+                            const double tmp24 = w5*(A_01_0 + A_10_0);
+                            const double tmp25 = w8*(A_11_0 + A_11_2);
+                            const double tmp26 = w2*(-A_01_3 - A_10_3);
+                            const double tmp27 = w5*(-A_01_1 - A_10_2);
+                            const double tmp28 = w1*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
+                            const double tmp29 = w2*(A_01_2 + A_10_1);
+                            const double tmp30 = w7*(-A_11_1 - A_11_3);
+                            const double tmp31 = w1*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
+                            const double tmp32 = w5*(-A_01_0 + A_10_2);
+                            const double tmp33 = w8*(-A_11_0 - A_11_2);
+                            const double tmp34 = w6*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
+                            const double tmp35 = w2*(A_01_3 - A_10_1);
+                            const double tmp36 = w5*(A_01_0 + A_10_3);
+                            const double tmp37 = w2*(-A_01_3 - A_10_0);
+                            const double tmp38 = w7*(-A_11_0 - A_11_2);
+                            const double tmp39 = w5*(-A_01_3 + A_10_1);
+                            const double tmp40 = w8*(-A_11_1 - A_11_3);
+                            const double tmp41 = w2*(A_01_0 - A_10_2);
+                            const double tmp42 = w5*(A_01_1 - A_10_3);
+                            const double tmp43 = w2*(-A_01_2 + A_10_0);
+                            const double tmp44 = w5*(A_01_2 - A_10_0);
+                            const double tmp45 = w2*(-A_01_1 + A_10_3);
+                            const double tmp46 = w5*(-A_01_0 + A_10_1);
+                            const double tmp47 = w2*(A_01_3 - A_10_2);
+                            const double tmp48 = w5*(-A_01_1 - A_10_1);
+                            const double tmp49 = w2*(A_01_2 + A_10_2);
+                            const double tmp50 = w5*(-A_01_3 + A_10_2);
+                            const double tmp51 = w2*(A_01_0 - A_10_1);
+                            const double tmp52 = w5*(-A_01_2 - A_10_1);
+                            const double tmp53 = w2*(A_01_1 + A_10_2);
+                            const double tmp54 = w5*(-A_01_2 - A_10_2);
+                            const double tmp55 = w2*(A_01_1 + A_10_1);
+                            EM_S[INDEX2(0,0,4)]+=tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp20 + tmp9;
+                            EM_S[INDEX2(0,1,4)]+=tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5;
+                            EM_S[INDEX2(0,2,4)]+=tmp31 + tmp34 + tmp38 + tmp39 + tmp40 + tmp41;
+                            EM_S[INDEX2(0,3,4)]+=tmp28 + tmp52 + tmp53 + tmp7 + tmp8;
+                            EM_S[INDEX2(1,0,4)]+=tmp0 + tmp2 + tmp3 + tmp31 + tmp50 + tmp51;
+                            EM_S[INDEX2(1,1,4)]+=tmp16 + tmp17 + tmp21 + tmp25 + tmp28 + tmp54 + tmp55;
+                            EM_S[INDEX2(1,2,4)]+=tmp10 + tmp6 + tmp7 + tmp8 + tmp9;
+                            EM_S[INDEX2(1,3,4)]+=tmp1 + tmp30 + tmp33 + tmp34 + tmp44 + tmp45;
+                            EM_S[INDEX2(2,0,4)]+=tmp1 + tmp34 + tmp38 + tmp40 + tmp42 + tmp43;
+                            EM_S[INDEX2(2,1,4)]+=tmp36 + tmp37 + tmp7 + tmp8 + tmp9;
+                            EM_S[INDEX2(2,2,4)]+=tmp15 + tmp19 + tmp22 + tmp23 + tmp28 + tmp48 + tmp49;
+                            EM_S[INDEX2(2,3,4)]+=tmp0 + tmp11 + tmp12 + tmp31 + tmp46 + tmp47;
+                            EM_S[INDEX2(3,0,4)]+=tmp27 + tmp28 + tmp29 + tmp7 + tmp8;
+                            EM_S[INDEX2(3,1,4)]+=tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
+                            EM_S[INDEX2(3,2,4)]+=tmp0 + tmp1 + tmp11 + tmp12 + tmp13 + tmp14;
+                            EM_S[INDEX2(3,3,4)]+=tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp9;
                         } else { // constant data
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double A_00 = A_p[INDEX4(k,0,m,0, numEq,2, numComp)];
-                                    const double A_01 = A_p[INDEX4(k,0,m,1, numEq,2, numComp)];
-                                    const double A_10 = A_p[INDEX4(k,1,m,0, numEq,2, numComp)];
-                                    const double A_11 = A_p[INDEX4(k,1,m,1, numEq,2, numComp)];
-                                    const double tmp0 = 6*w1*(A_01 - A_10);
-                                    const double tmp1 = 6*w1*(A_01 + A_10);
-                                    const double tmp2 = 6*w1*(-A_01 - A_10);
-                                    const double tmp3 = 6*w1*(-A_01 + A_10);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
-                                }
-                            }
-                        }
-                    }
-                    ///////////////
-                    // process B //
-                    ///////////////
-                    if (!B.isEmpty()) {
-                        addEM_S=true;
-                        const double* B_p=B.getSampleDataRO(e);
-                        if (B.actsExpanded()) {
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double B_0_0 = B_p[INDEX4(k,0,m,0, numEq,2,numComp)];
-                                    const double B_1_0 = B_p[INDEX4(k,1,m,0, numEq,2,numComp)];
-                                    const double B_0_1 = B_p[INDEX4(k,0,m,1, numEq,2,numComp)];
-                                    const double B_1_1 = B_p[INDEX4(k,1,m,1, numEq,2,numComp)];
-                                    const double B_0_2 = B_p[INDEX4(k,0,m,2, numEq,2,numComp)];
-                                    const double B_1_2 = B_p[INDEX4(k,1,m,2, numEq,2,numComp)];
-                                    const double B_0_3 = B_p[INDEX4(k,0,m,3, numEq,2,numComp)];
-                                    const double B_1_3 = B_p[INDEX4(k,1,m,3, numEq,2,numComp)];
-                                    const double tmp0 = w11*(B_1_0 + B_1_1);
-                                    const double tmp1 = w14*(B_1_2 + B_1_3);
-                                    const double tmp2 = w15*(-B_0_1 - B_0_3);
-                                    const double tmp3 = w10*(-B_0_0 - B_0_2);
-                                    const double tmp4 = w11*(B_1_2 + B_1_3);
-                                    const double tmp5 = w14*(B_1_0 + B_1_1);
-                                    const double tmp6 = w11*(-B_1_2 - B_1_3);
-                                    const double tmp7 = w14*(-B_1_0 - B_1_1);
-                                    const double tmp8 = w11*(-B_1_0 - B_1_1);
-                                    const double tmp9 = w14*(-B_1_2 - B_1_3);
-                                    const double tmp10 = w10*(-B_0_1 - B_0_3);
-                                    const double tmp11 = w15*(-B_0_0 - B_0_2);
-                                    const double tmp12 = w15*(B_0_0 + B_0_2);
-                                    const double tmp13 = w10*(B_0_1 + B_0_3);
-                                    const double tmp14 = w10*(B_0_0 + B_0_2);
-                                    const double tmp15 = w15*(B_0_1 + B_0_3);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=B_0_0*w12 + B_0_1*w10 + B_0_2*w15 + B_0_3*w13 + B_1_0*w16 + B_1_1*w14 + B_1_2*w11 + B_1_3*w17;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=B_0_0*w10 + B_0_1*w12 + B_0_2*w13 + B_0_3*w15 + tmp0 + tmp1;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=B_1_0*w11 + B_1_1*w17 + B_1_2*w16 + B_1_3*w14 + tmp14 + tmp15;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-B_0_0*w12 - B_0_1*w10 - B_0_2*w15 - B_0_3*w13 + tmp0 + tmp1;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-B_0_0*w10 - B_0_1*w12 - B_0_2*w13 - B_0_3*w15 + B_1_0*w14 + B_1_1*w16 + B_1_2*w17 + B_1_3*w11;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=B_1_0*w17 + B_1_1*w11 + B_1_2*w14 + B_1_3*w16 + tmp10 + tmp11;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-B_1_0*w16 - B_1_1*w14 - B_1_2*w11 - B_1_3*w17 + tmp14 + tmp15;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=B_0_0*w15 + B_0_1*w13 + B_0_2*w12 + B_0_3*w10 - B_1_0*w11 - B_1_1*w17 - B_1_2*w16 - B_1_3*w14;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=B_0_0*w13 + B_0_1*w15 + B_0_2*w10 + B_0_3*w12 + tmp6 + tmp7;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=-B_1_0*w14 - B_1_1*w16 - B_1_2*w17 - B_1_3*w11 + tmp10 + tmp11;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-B_0_0*w15 - B_0_1*w13 - B_0_2*w12 - B_0_3*w10 + tmp6 + tmp7;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-B_0_0*w13 - B_0_1*w15 - B_0_2*w10 - B_0_3*w12 - B_1_0*w17 - B_1_1*w11 - B_1_2*w14 - B_1_3*w16;
-                                }
-                            }
+                            const double A_00 = A_p[INDEX2(0,0,2)];
+                            const double A_01 = A_p[INDEX2(0,1,2)];
+                            const double A_10 = A_p[INDEX2(1,0,2)];
+                            const double A_11 = A_p[INDEX2(1,1,2)];
+                            const double tmp0 = 6*w1*(A_01 - A_10);
+                            const double tmp1 = 6*w1*(A_01 + A_10);
+                            const double tmp2 = 6*w1*(-A_01 - A_10);
+                            const double tmp3 = 6*w1*(-A_01 + A_10);
+                            EM_S[INDEX2(0,0,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
+                            EM_S[INDEX2(0,1,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
+                            EM_S[INDEX2(0,2,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
+                            EM_S[INDEX2(0,3,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
+                            EM_S[INDEX2(1,0,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
+                            EM_S[INDEX2(1,1,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
+                            EM_S[INDEX2(1,2,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
+                            EM_S[INDEX2(1,3,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
+                            EM_S[INDEX2(2,0,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
+                            EM_S[INDEX2(2,1,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
+                            EM_S[INDEX2(2,2,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
+                            EM_S[INDEX2(2,3,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
+                            EM_S[INDEX2(3,0,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
+                            EM_S[INDEX2(3,1,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
+                            EM_S[INDEX2(3,2,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
+                            EM_S[INDEX2(3,3,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
+                        }
+                    }
+                    ///////////////
+                    // process B //
+                    ///////////////
+                    if (!B.isEmpty()) {
+                        const double* B_p=B.getSampleDataRO(e);
+                        if (B.actsExpanded()) {
+                            const double B_0_0 = B_p[INDEX2(0,0,2)];
+                            const double B_1_0 = B_p[INDEX2(1,0,2)];
+                            const double B_0_1 = B_p[INDEX2(0,1,2)];
+                            const double B_1_1 = B_p[INDEX2(1,1,2)];
+                            const double B_0_2 = B_p[INDEX2(0,2,2)];
+                            const double B_1_2 = B_p[INDEX2(1,2,2)];
+                            const double B_0_3 = B_p[INDEX2(0,3,2)];
+                            const double B_1_3 = B_p[INDEX2(1,3,2)];
+                            const double tmp0 = w11*(B_1_0 + B_1_1);
+                            const double tmp1 = w14*(B_1_2 + B_1_3);
+                            const double tmp2 = w15*(-B_0_1 - B_0_3);
+                            const double tmp3 = w10*(-B_0_0 - B_0_2);
+                            const double tmp4 = w11*(B_1_2 + B_1_3);
+                            const double tmp5 = w14*(B_1_0 + B_1_1);
+                            const double tmp6 = w11*(-B_1_2 - B_1_3);
+                            const double tmp7 = w14*(-B_1_0 - B_1_1);
+                            const double tmp8 = w11*(-B_1_0 - B_1_1);
+                            const double tmp9 = w14*(-B_1_2 - B_1_3);
+                            const double tmp10 = w10*(-B_0_1 - B_0_3);
+                            const double tmp11 = w15*(-B_0_0 - B_0_2);
+                            const double tmp12 = w15*(B_0_0 + B_0_2);
+                            const double tmp13 = w10*(B_0_1 + B_0_3);
+                            const double tmp14 = w10*(B_0_0 + B_0_2);
+                            const double tmp15 = w15*(B_0_1 + B_0_3);
+                            EM_S[INDEX2(0,0,4)]+=B_0_0*w12 + B_0_1*w10 + B_0_2*w15 + B_0_3*w13 + B_1_0*w16 + B_1_1*w14 + B_1_2*w11 + B_1_3*w17;
+                            EM_S[INDEX2(0,1,4)]+=B_0_0*w10 + B_0_1*w12 + B_0_2*w13 + B_0_3*w15 + tmp0 + tmp1;
+                            EM_S[INDEX2(0,2,4)]+=B_1_0*w11 + B_1_1*w17 + B_1_2*w16 + B_1_3*w14 + tmp14 + tmp15;
+                            EM_S[INDEX2(0,3,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
+                            EM_S[INDEX2(1,0,4)]+=-B_0_0*w12 - B_0_1*w10 - B_0_2*w15 - B_0_3*w13 + tmp0 + tmp1;
+                            EM_S[INDEX2(1,1,4)]+=-B_0_0*w10 - B_0_1*w12 - B_0_2*w13 - B_0_3*w15 + B_1_0*w14 + B_1_1*w16 + B_1_2*w17 + B_1_3*w11;
+                            EM_S[INDEX2(1,2,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
+                            EM_S[INDEX2(1,3,4)]+=B_1_0*w17 + B_1_1*w11 + B_1_2*w14 + B_1_3*w16 + tmp10 + tmp11;
+                            EM_S[INDEX2(2,0,4)]+=-B_1_0*w16 - B_1_1*w14 - B_1_2*w11 - B_1_3*w17 + tmp14 + tmp15;
+                            EM_S[INDEX2(2,1,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
+                            EM_S[INDEX2(2,2,4)]+=B_0_0*w15 + B_0_1*w13 + B_0_2*w12 + B_0_3*w10 - B_1_0*w11 - B_1_1*w17 - B_1_2*w16 - B_1_3*w14;
+                            EM_S[INDEX2(2,3,4)]+=B_0_0*w13 + B_0_1*w15 + B_0_2*w10 + B_0_3*w12 + tmp6 + tmp7;
+                            EM_S[INDEX2(3,0,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
+                            EM_S[INDEX2(3,1,4)]+=-B_1_0*w14 - B_1_1*w16 - B_1_2*w17 - B_1_3*w11 + tmp10 + tmp11;
+                            EM_S[INDEX2(3,2,4)]+=-B_0_0*w15 - B_0_1*w13 - B_0_2*w12 - B_0_3*w10 + tmp6 + tmp7;
+                            EM_S[INDEX2(3,3,4)]+=-B_0_0*w13 - B_0_1*w15 - B_0_2*w10 - B_0_3*w12 - B_1_0*w17 - B_1_1*w11 - B_1_2*w14 - B_1_3*w16;
                         } else { // constant data
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double wB0 = B_p[INDEX3(k,0,m,numEq,2)]*w18;
-                                    const double wB1 = B_p[INDEX3(k,1,m,numEq,2)]*w19;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+= 2*wB0 + 2*wB1;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+= 2*wB0 +   wB1;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=   wB0 + 2*wB1;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=   wB0 +   wB1;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-2*wB0 +   wB1;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-2*wB0 + 2*wB1;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=  -wB0 +   wB1;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=  -wB0 + 2*wB1;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=   wB0 - 2*wB1;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=   wB0 -   wB1;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+= 2*wB0 - 2*wB1;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+= 2*wB0 -   wB1;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=  -wB0 -   wB1;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=  -wB0 - 2*wB1;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-2*wB0 -   wB1;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-2*wB0 - 2*wB1;
-                                }
-                            }
+                            const double B_0 = B_p[0];
+                            const double B_1 = B_p[1];
+                            EM_S[INDEX2(0,0,4)]+= 2*B_0*w18 + 2*B_1*w19;
+                            EM_S[INDEX2(0,1,4)]+= 2*B_0*w18 +   B_1*w19;
+                            EM_S[INDEX2(0,2,4)]+=   B_0*w18 + 2*B_1*w19;
+                            EM_S[INDEX2(0,3,4)]+=   B_0*w18 +   B_1*w19;
+                            EM_S[INDEX2(1,0,4)]+=-2*B_0*w18 +   B_1*w19;
+                            EM_S[INDEX2(1,1,4)]+=-2*B_0*w18 + 2*B_1*w19;
+                            EM_S[INDEX2(1,2,4)]+=  -B_0*w18 +   B_1*w19;
+                            EM_S[INDEX2(1,3,4)]+=  -B_0*w18 + 2*B_1*w19;
+                            EM_S[INDEX2(2,0,4)]+=   B_0*w18 - 2*B_1*w19;
+                            EM_S[INDEX2(2,1,4)]+=   B_0*w18 -   B_1*w19;
+                            EM_S[INDEX2(2,2,4)]+= 2*B_0*w18 - 2*B_1*w19;
+                            EM_S[INDEX2(2,3,4)]+= 2*B_0*w18 -   B_1*w19;
+                            EM_S[INDEX2(3,0,4)]+=  -B_0*w18 -   B_1*w19;
+                            EM_S[INDEX2(3,1,4)]+=  -B_0*w18 - 2*B_1*w19;
+                            EM_S[INDEX2(3,2,4)]+=-2*B_0*w18 -   B_1*w19;
+                            EM_S[INDEX2(3,3,4)]+=-2*B_0*w18 - 2*B_1*w19;
+                        }
+                    }
+                    ///////////////
+                    // process C //
+                    ///////////////
+                    if (!C.isEmpty()) {
+                        const double* C_p=C.getSampleDataRO(e);
+                        if (C.actsExpanded()) {
+                            const double C_0_0 = C_p[INDEX2(0,0,2)];
+                            const double C_1_0 = C_p[INDEX2(1,0,2)];
+                            const double C_0_1 = C_p[INDEX2(0,1,2)];
+                            const double C_1_1 = C_p[INDEX2(1,1,2)];
+                            const double C_0_2 = C_p[INDEX2(0,2,2)];
+                            const double C_1_2 = C_p[INDEX2(1,2,2)];
+                            const double C_0_3 = C_p[INDEX2(0,3,2)];
+                            const double C_1_3 = C_p[INDEX2(1,3,2)];
+                            const double tmp0 = w11*(C_1_0 + C_1_1);
+                            const double tmp1 = w14*(C_1_2 + C_1_3);
+                            const double tmp2 = w15*(C_0_0 + C_0_2);
+                            const double tmp3 = w10*(C_0_1 + C_0_3);
+                            const double tmp4 = w11*(-C_1_0 - C_1_1);
+                            const double tmp5 = w14*(-C_1_2 - C_1_3);
+                            const double tmp6 = w11*(-C_1_2 - C_1_3);
+                            const double tmp7 = w14*(-C_1_0 - C_1_1);
+                            const double tmp8 = w11*(C_1_2 + C_1_3);
+                            const double tmp9 = w14*(C_1_0 + C_1_1);
+                            const double tmp10 = w10*(-C_0_1 - C_0_3);
+                            const double tmp11 = w15*(-C_0_0 - C_0_2);
+                            const double tmp12 = w15*(-C_0_1 - C_0_3);
+                            const double tmp13 = w10*(-C_0_0 - C_0_2);
+                            const double tmp14 = w10*(C_0_0 + C_0_2);
+                            const double tmp15 = w15*(C_0_1 + C_0_3);
+                            EM_S[INDEX2(0,0,4)]+=C_0_0*w12 + C_0_1*w10 + C_0_2*w15 + C_0_3*w13 + C_1_0*w16 + C_1_1*w14 + C_1_2*w11 + C_1_3*w17;
+                            EM_S[INDEX2(0,1,4)]+=-C_0_0*w12 - C_0_1*w10 - C_0_2*w15 - C_0_3*w13 + tmp0 + tmp1;
+                            EM_S[INDEX2(0,2,4)]+=-C_1_0*w16 - C_1_1*w14 - C_1_2*w11 - C_1_3*w17 + tmp14 + tmp15;
+                            EM_S[INDEX2(0,3,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
+                            EM_S[INDEX2(1,0,4)]+=C_0_0*w10 + C_0_1*w12 + C_0_2*w13 + C_0_3*w15 + tmp0 + tmp1;
+                            EM_S[INDEX2(1,1,4)]+=-C_0_0*w10 - C_0_1*w12 - C_0_2*w13 - C_0_3*w15 + C_1_0*w14 + C_1_1*w16 + C_1_2*w17 + C_1_3*w11;
+                            EM_S[INDEX2(1,2,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
+                            EM_S[INDEX2(1,3,4)]+=-C_1_0*w14 - C_1_1*w16 - C_1_2*w17 - C_1_3*w11 + tmp10 + tmp11;
+                            EM_S[INDEX2(2,0,4)]+=C_1_0*w11 + C_1_1*w17 + C_1_2*w16 + C_1_3*w14 + tmp14 + tmp15;
+                            EM_S[INDEX2(2,1,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
+                            EM_S[INDEX2(2,2,4)]+=C_0_0*w15 + C_0_1*w13 + C_0_2*w12 + C_0_3*w10 - C_1_0*w11 - C_1_1*w17 - C_1_2*w16 - C_1_3*w14;
+                            EM_S[INDEX2(2,3,4)]+=-C_0_0*w15 - C_0_1*w13 - C_0_2*w12 - C_0_3*w10 + tmp6 + tmp7;
+                            EM_S[INDEX2(3,0,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
+                            EM_S[INDEX2(3,1,4)]+=C_1_0*w17 + C_1_1*w11 + C_1_2*w14 + C_1_3*w16 + tmp10 + tmp11;
+                            EM_S[INDEX2(3,2,4)]+=C_0_0*w13 + C_0_1*w15 + C_0_2*w10 + C_0_3*w12 + tmp6 + tmp7;
+                            EM_S[INDEX2(3,3,4)]+=-C_0_0*w13 - C_0_1*w15 - C_0_2*w10 - C_0_3*w12 - C_1_0*w17 - C_1_1*w11 - C_1_2*w14 - C_1_3*w16;
+                        } else { // constant data
+                            const double C_0 = C_p[0];
+                            const double C_1 = C_p[1];
+                            EM_S[INDEX2(0,0,4)]+= 2*C_0*w18 + 2*C_1*w19;
+                            EM_S[INDEX2(0,1,4)]+=-2*C_0*w18 +   C_1*w19;
+                            EM_S[INDEX2(0,2,4)]+=   C_0*w18 - 2*C_1*w19;
+                            EM_S[INDEX2(0,3,4)]+=  -C_0*w18 -   C_1*w19;
+                            EM_S[INDEX2(1,0,4)]+= 2*C_0*w18 +   C_1*w19;
+                            EM_S[INDEX2(1,1,4)]+=-2*C_0*w18 + 2*C_1*w19;
+                            EM_S[INDEX2(1,2,4)]+=   C_0*w18 -   C_1*w19;
+                            EM_S[INDEX2(1,3,4)]+=  -C_0*w18 - 2*C_1*w19;
+                            EM_S[INDEX2(2,0,4)]+=   C_0*w18 + 2*C_1*w19;
+                            EM_S[INDEX2(2,1,4)]+=  -C_0*w18 +   C_1*w19;
+                            EM_S[INDEX2(2,2,4)]+= 2*C_0*w18 - 2*C_1*w19;
+                            EM_S[INDEX2(2,3,4)]+=-2*C_0*w18 -   C_1*w19;
+                            EM_S[INDEX2(3,0,4)]+=   C_0*w18 +   C_1*w19;
+                            EM_S[INDEX2(3,1,4)]+=  -C_0*w18 + 2*C_1*w19;
+                            EM_S[INDEX2(3,2,4)]+= 2*C_0*w18 -   C_1*w19;
+                            EM_S[INDEX2(3,3,4)]+=-2*C_0*w18 - 2*C_1*w19;
+                        }
+                    }
+                    ///////////////
+                    // process D //
+                    ///////////////
+                    if (!D.isEmpty()) {
+                        const double* D_p=D.getSampleDataRO(e);
+                        if (D.actsExpanded()) {
+                            const double D_0 = D_p[0];
+                            const double D_1 = D_p[1];
+                            const double D_2 = D_p[2];
+                            const double D_3 = D_p[3];
+                            const double tmp0 = w21*(D_2 + D_3);
+                            const double tmp1 = w20*(D_0 + D_1);
+                            const double tmp2 = w22*(D_0 + D_1 + D_2 + D_3);
+                            const double tmp3 = w21*(D_0 + D_1);
+                            const double tmp4 = w20*(D_2 + D_3);
+                            const double tmp5 = w22*(D_1 + D_2);
+                            const double tmp6 = w21*(D_0 + D_2);
+                            const double tmp7 = w20*(D_1 + D_3);
+                            const double tmp8 = w21*(D_1 + D_3);
+                            const double tmp9 = w20*(D_0 + D_2);
+                            const double tmp10 = w22*(D_0 + D_3);
+                            EM_S[INDEX2(0,0,4)]+=D_0*w23 + D_3*w24 + tmp5;
+                            EM_S[INDEX2(0,1,4)]+=tmp0 + tmp1;
+                            EM_S[INDEX2(0,2,4)]+=tmp8 + tmp9;
+                            EM_S[INDEX2(0,3,4)]+=tmp2;
+                            EM_S[INDEX2(1,0,4)]+=tmp0 + tmp1;
+                            EM_S[INDEX2(1,1,4)]+=D_1*w23 + D_2*w24 + tmp10;
+                            EM_S[INDEX2(1,2,4)]+=tmp2;
+                            EM_S[INDEX2(1,3,4)]+=tmp6 + tmp7;
+                            EM_S[INDEX2(2,0,4)]+=tmp8 + tmp9;
+                            EM_S[INDEX2(2,1,4)]+=tmp2;
+                            EM_S[INDEX2(2,2,4)]+=D_1*w24 + D_2*w23 + tmp10;
+                            EM_S[INDEX2(2,3,4)]+=tmp3 + tmp4;
+                            EM_S[INDEX2(3,0,4)]+=tmp2;
+                            EM_S[INDEX2(3,1,4)]+=tmp6 + tmp7;
+                            EM_S[INDEX2(3,2,4)]+=tmp3 + tmp4;
+                            EM_S[INDEX2(3,3,4)]+=D_0*w24 + D_3*w23 + tmp5;
+                        } else { // constant data
+                            const double D_0 = D_p[0];
+                            EM_S[INDEX2(0,0,4)]+=16*D_0*w22;
+                            EM_S[INDEX2(0,1,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(0,2,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(0,3,4)]+=4*D_0*w22;
+                            EM_S[INDEX2(1,0,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(1,1,4)]+=16*D_0*w22;
+                            EM_S[INDEX2(1,2,4)]+=4*D_0*w22;
+                            EM_S[INDEX2(1,3,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(2,0,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(2,1,4)]+=4*D_0*w22;
+                            EM_S[INDEX2(2,2,4)]+=16*D_0*w22;
+                            EM_S[INDEX2(2,3,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(3,0,4)]+=4*D_0*w22;
+                            EM_S[INDEX2(3,1,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(3,2,4)]+=8*D_0*w22;
+                            EM_S[INDEX2(3,3,4)]+=16*D_0*w22;
+                        }
+                    }
+                    ///////////////
+                    // process X //
+                    ///////////////
+                    if (!X.isEmpty()) {
+                        const double* X_p=X.getSampleDataRO(e);
+                        if (X.actsExpanded()) {
+                            const double X_0_0 = X_p[INDEX2(0,0,2)];
+                            const double X_1_0 = X_p[INDEX2(1,0,2)];
+                            const double X_0_1 = X_p[INDEX2(0,1,2)];
+                            const double X_1_1 = X_p[INDEX2(1,1,2)];
+                            const double X_0_2 = X_p[INDEX2(0,2,2)];
+                            const double X_1_2 = X_p[INDEX2(1,2,2)];
+                            const double X_0_3 = X_p[INDEX2(0,3,2)];
+                            const double X_1_3 = X_p[INDEX2(1,3,2)];
+                            const double tmp0 = 6*w15*(X_0_2 + X_0_3);
+                            const double tmp1 = 6*w10*(X_0_0 + X_0_1);
+                            const double tmp2 = 6*w11*(X_1_0 + X_1_2);
+                            const double tmp3 = 6*w14*(X_1_1 + X_1_3);
+                            const double tmp4 = 6*w11*(X_1_1 + X_1_3);
+                            const double tmp5 = w25*(X_0_0 + X_0_1);
+                            const double tmp6 = w26*(X_0_2 + X_0_3);
+                            const double tmp7 = 6*w14*(X_1_0 + X_1_2);
+                            const double tmp8 = w27*(X_1_0 + X_1_2);
+                            const double tmp9 = w28*(X_1_1 + X_1_3);
+                            const double tmp10 = w25*(-X_0_2 - X_0_3);
+                            const double tmp11 = w26*(-X_0_0 - X_0_1);
+                            const double tmp12 = w27*(X_1_1 + X_1_3);
+                            const double tmp13 = w28*(X_1_0 + X_1_2);
+                            const double tmp14 = w25*(X_0_2 + X_0_3);
+                            const double tmp15 = w26*(X_0_0 + X_0_1);
+                            EM_F[0]+=tmp0 + tmp1 + tmp2 + tmp3;
+                            EM_F[1]+=tmp4 + tmp5 + tmp6 + tmp7;
+                            EM_F[2]+=tmp10 + tmp11 + tmp8 + tmp9;
+                            EM_F[3]+=tmp12 + tmp13 + tmp14 + tmp15;
+                        } else { // constant data
+                            const double X_0 = X_p[0];
+                            const double X_1 = X_p[1];
+                            EM_F[0]+= 6*X_0*w18 + 6*X_1*w19;
+                            EM_F[1]+=-6*X_0*w18 + 6*X_1*w19;
+                            EM_F[2]+= 6*X_0*w18 - 6*X_1*w19;
+                            EM_F[3]+=-6*X_0*w18 - 6*X_1*w19;
+                        }
+                    }
+                    ///////////////
+                    // process Y //
+                    ///////////////
+                    if (!Y.isEmpty()) {
+                        const double* Y_p=Y.getSampleDataRO(e);
+                        if (Y.actsExpanded()) {
+                            const double Y_0 = Y_p[0];
+                            const double Y_1 = Y_p[1];
+                            const double Y_2 = Y_p[2];
+                            const double Y_3 = Y_p[3];
+                            const double tmp0 = 6*w22*(Y_1 + Y_2);
+                            const double tmp1 = 6*w22*(Y_0 + Y_3);
+                            EM_F[0]+=6*Y_0*w20 + 6*Y_3*w21 + tmp0;
+                            EM_F[1]+=6*Y_1*w20 + 6*Y_2*w21 + tmp1;
+                            EM_F[2]+=6*Y_1*w21 + 6*Y_2*w20 + tmp1;
+                            EM_F[3]+=6*Y_0*w21 + 6*Y_3*w20 + tmp0;
+                        } else { // constant data
+                            EM_F[0]+=36*Y_p[0]*w22;
+                            EM_F[1]+=36*Y_p[0]*w22;
+                            EM_F[2]+=36*Y_p[0]*w22;
+                            EM_F[3]+=36*Y_p[0]*w22;
+                        }
+                    }
+
+                    // add to matrix (if addEM_S) and RHS (if addEM_F)
+                    const index_t firstNode=m_NN[0]*k1+k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
+                } // end k0 loop
+            } // end k1 loop
+        } // end of colouring
+    } // end of parallel region
+}
+
+/****************************************************************************/
+// PDE SINGLE BOUNDARY
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
+                                Data& rhs, const Data& d, const Data& y) const
+{
+    const double SQRT3 = 1.73205080756887719318;
+    const double w5 = m_dx[0]/12;
+    const double w6 = w5*(SQRT3 + 2);
+    const double w7 = w5*(-SQRT3 + 2);
+    const double w8 = w5*(SQRT3 + 3);
+    const double w9 = w5*(-SQRT3 + 3);
+    const double w2 = m_dx[1]/12;
+    const double w0 = w2*(SQRT3 + 2);
+    const double w1 = w2*(-SQRT3 + 2);
+    const double w3 = w2*(SQRT3 + 3);
+    const double w4 = w2*(-SQRT3 + 3);
+    const int NE0 = m_NE[0];
+    const int NE1 = m_NE[1];
+    const bool addEM_S = !d.isEmpty();
+    const bool addEM_F = !y.isEmpty();
+    rhs.requireWrite();
+
+#pragma omp parallel
+    {
+        vector<double> EM_S(4*4);
+        vector<double> EM_F(4);
+
+        if (domain->m_faceOffset[0] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[1] = 0;
+                EM_F[3] = 0;
+            }
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    ///////////////
+                    // process d //
+                    ///////////////
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(k1);
+                        if (d.actsExpanded()) {
+                            const double d_0 = d_p[0];
+                            const double d_1 = d_p[1];
+                            const double tmp0 = w2*(d_0 + d_1);
+                            EM_S[INDEX2(0,0,4)] = d_0*w0 + d_1*w1;
+                            EM_S[INDEX2(2,0,4)] = tmp0;
+                            EM_S[INDEX2(0,2,4)] = tmp0;
+                            EM_S[INDEX2(2,2,4)] = d_0*w1 + d_1*w0;
+                        } else { // constant data
+                            EM_S[INDEX2(0,0,4)] = 4*d_p[0]*w2;
+                            EM_S[INDEX2(2,0,4)] = 2*d_p[0]*w2;
+                            EM_S[INDEX2(0,2,4)] = 2*d_p[0]*w2;
+                            EM_S[INDEX2(2,2,4)] = 4*d_p[0]*w2;
+                        }
+                    }
+                    ///////////////
+                    // process y //
+                    ///////////////
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(k1);
+                        if (y.actsExpanded()) {
+                            EM_F[0] = w3*y_p[0] + w4*y_p[1];
+                            EM_F[2] = w3*y_p[1] + w4*y_p[0];
+                        } else { // constant data
+                            EM_F[0] = 6*w2*y_p[0];
+                            EM_F[2] = 6*w2*y_p[0];
+                        }
+                    }
+                    const index_t firstNode=m_NN[0]*k1;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
+                }
+            } // end colouring
+        }
+
+        if (domain->m_faceOffset[1] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[0] = 0;
+                EM_F[2] = 0;
+            }
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    const index_t e = domain->m_faceOffset[1]+k1;
+                    ///////////////
+                    // process d //
+                    ///////////////
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        if (d.actsExpanded()) {
+                            const double d_0 = d_p[0];
+                            const double d_1 = d_p[1];
+                            const double tmp0 = w2*(d_0 + d_1);
+                            EM_S[INDEX2(1,1,4)] = d_0*w0 + d_1*w1;
+                            EM_S[INDEX2(3,1,4)] = tmp0;
+                            EM_S[INDEX2(1,3,4)] = tmp0;
+                            EM_S[INDEX2(3,3,4)] = d_0*w1 + d_1*w0;
+                        } else { // constant data
+                            EM_S[INDEX2(1,1,4)] = 4*d_p[0]*w2;
+                            EM_S[INDEX2(3,1,4)] = 2*d_p[0]*w2;
+                            EM_S[INDEX2(1,3,4)] = 2*d_p[0]*w2;
+                            EM_S[INDEX2(3,3,4)] = 4*d_p[0]*w2;
+                        }
+                    }
+                    ///////////////
+                    // process y //
+                    ///////////////
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        if (y.actsExpanded()) {
+                            EM_F[1] = w3*y_p[0] + w4*y_p[1];
+                            EM_F[3] = w3*y_p[1] + w4*y_p[0];
+                        } else { // constant data
+                            EM_F[1] = 6*w2*y_p[0];
+                            EM_F[3] = 6*w2*y_p[0];
                         }
                     }
+                    const index_t firstNode=m_NN[0]*(k1+1)-2;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
+                }
+            } // end colouring
+        }
+
+        if (domain->m_faceOffset[2] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[2] = 0;
+                EM_F[3] = 0;
+            }
+
+            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
+#pragma omp for
+                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
+                    const index_t e = domain->m_faceOffset[2]+k0;
                     ///////////////
-                    // process C //
+                    // process d //
                     ///////////////
-                    if (!C.isEmpty()) {
-                        addEM_S=true;
-                        const double* C_p=C.getSampleDataRO(e);
-                        if (C.actsExpanded()) {
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double C_0_0 = C_p[INDEX4(k,m,0, 0, numEq,numComp,2)];
-                                    const double C_1_0 = C_p[INDEX4(k,m,1, 0, numEq,numComp,2)];
-                                    const double C_0_1 = C_p[INDEX4(k,m,0, 1, numEq,numComp,2)];
-                                    const double C_1_1 = C_p[INDEX4(k,m,1, 1, numEq,numComp,2)];
-                                    const double C_0_2 = C_p[INDEX4(k,m,0, 2, numEq,numComp,2)];
-                                    const double C_1_2 = C_p[INDEX4(k,m,1, 2, numEq,numComp,2)];
-                                    const double C_0_3 = C_p[INDEX4(k,m,0, 3, numEq,numComp,2)];
-                                    const double C_1_3 = C_p[INDEX4(k,m,1, 3, numEq,numComp,2)];
-                                    const double tmp0 = w11*(C_1_0 + C_1_1);
-                                    const double tmp1 = w14*(C_1_2 + C_1_3);
-                                    const double tmp2 = w15*(C_0_0 + C_0_2);
-                                    const double tmp3 = w10*(C_0_1 + C_0_3);
-                                    const double tmp4 = w11*(-C_1_0 - C_1_1);
-                                    const double tmp5 = w14*(-C_1_2 - C_1_3);
-                                    const double tmp6 = w11*(-C_1_2 - C_1_3);
-                                    const double tmp7 = w14*(-C_1_0 - C_1_1);
-                                    const double tmp8 = w11*(C_1_2 + C_1_3);
-                                    const double tmp9 = w14*(C_1_0 + C_1_1);
-                                    const double tmp10 = w10*(-C_0_1 - C_0_3);
-                                    const double tmp11 = w15*(-C_0_0 - C_0_2);
-                                    const double tmp12 = w15*(-C_0_1 - C_0_3);
-                                    const double tmp13 = w10*(-C_0_0 - C_0_2);
-                                    const double tmp14 = w10*(C_0_0 + C_0_2);
-                                    const double tmp15 = w15*(C_0_1 + C_0_3);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=C_0_0*w12 + C_0_1*w10 + C_0_2*w15 + C_0_3*w13 + C_1_0*w16 + C_1_1*w14 + C_1_2*w11 + C_1_3*w17;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-C_0_0*w12 - C_0_1*w10 - C_0_2*w15 - C_0_3*w13 + tmp0 + tmp1;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-C_1_0*w16 - C_1_1*w14 - C_1_2*w11 - C_1_3*w17 + tmp14 + tmp15;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=C_0_0*w10 + C_0_1*w12 + C_0_2*w13 + C_0_3*w15 + tmp0 + tmp1;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-C_0_0*w10 - C_0_1*w12 - C_0_2*w13 - C_0_3*w15 + C_1_0*w14 + C_1_1*w16 + C_1_2*w17 + C_1_3*w11;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=-C_1_0*w14 - C_1_1*w16 - C_1_2*w17 - C_1_3*w11 + tmp10 + tmp11;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=C_1_0*w11 + C_1_1*w17 + C_1_2*w16 + C_1_3*w14 + tmp14 + tmp15;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=C_0_0*w15 + C_0_1*w13 + C_0_2*w12 + C_0_3*w10 - C_1_0*w11 - C_1_1*w17 - C_1_2*w16 - C_1_3*w14;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-C_0_0*w15 - C_0_1*w13 - C_0_2*w12 - C_0_3*w10 + tmp6 + tmp7;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=C_1_0*w17 + C_1_1*w11 + C_1_2*w14 + C_1_3*w16 + tmp10 + tmp11;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=C_0_0*w13 + C_0_1*w15 + C_0_2*w10 + C_0_3*w12 + tmp6 + tmp7;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-C_0_0*w13 - C_0_1*w15 - C_0_2*w10 - C_0_3*w12 - C_1_0*w17 - C_1_1*w11 - C_1_2*w14 - C_1_3*w16;
-                                }
-                            }
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        if (d.actsExpanded()) {
+                            const double d_0 = d_p[0];
+                            const double d_1 = d_p[1];
+                            const double tmp0 = w5*(d_0 + d_1);
+                            EM_S[INDEX2(0,0,4)] = d_0*w6 + d_1*w7;
+                            EM_S[INDEX2(1,0,4)] = tmp0;
+                            EM_S[INDEX2(0,1,4)] = tmp0;
+                            EM_S[INDEX2(1,1,4)] = d_0*w7 + d_1*w6;
                         } else { // constant data
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double wC0 = C_p[INDEX3(k,m,0,numEq,numComp)]*w18;
-                                    const double wC1 = C_p[INDEX3(k,m,1,numEq,numComp)]*w19;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+= 2*wC0 + 2*wC1;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-2*wC0 +   wC1;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=   wC0 - 2*wC1;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=  -wC0 -   wC1;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+= 2*wC0 +   wC1;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-2*wC0 + 2*wC1;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=   wC0 -   wC1;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=  -wC0 - 2*wC1;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=   wC0 + 2*wC1;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=  -wC0 +   wC1;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+= 2*wC0 - 2*wC1;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-2*wC0 -   wC1;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=   wC0 +   wC1;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=  -wC0 + 2*wC1;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+= 2*wC0 -   wC1;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-2*wC0 - 2*wC1;
-                                }
-                            }
+                            EM_S[INDEX2(0,0,4)] = 4*d_p[0]*w5;
+                            EM_S[INDEX2(1,0,4)] = 2*d_p[0]*w5;
+                            EM_S[INDEX2(0,1,4)] = 2*d_p[0]*w5;
+                            EM_S[INDEX2(1,1,4)] = 4*d_p[0]*w5;
                         }
                     }
                     ///////////////
-                    // process D //
+                    // process y //
                     ///////////////
-                    if (!D.isEmpty()) {
-                        addEM_S=true;
-                        const double* D_p=D.getSampleDataRO(e);
-                        if (D.actsExpanded()) {
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double D_0 = D_p[INDEX3(k,m,0,numEq,numComp)];
-                                    const double D_1 = D_p[INDEX3(k,m,1,numEq,numComp)];
-                                    const double D_2 = D_p[INDEX3(k,m,2,numEq,numComp)];
-                                    const double D_3 = D_p[INDEX3(k,m,3,numEq,numComp)];
-                                    const double tmp0 = w21*(D_2 + D_3);
-                                    const double tmp1 = w20*(D_0 + D_1);
-                                    const double tmp2 = w22*(D_0 + D_1 + D_2 + D_3);
-                                    const double tmp3 = w21*(D_0 + D_1);
-                                    const double tmp4 = w20*(D_2 + D_3);
-                                    const double tmp5 = w22*(D_1 + D_2);
-                                    const double tmp6 = w21*(D_0 + D_2);
-                                    const double tmp7 = w20*(D_1 + D_3);
-                                    const double tmp8 = w21*(D_1 + D_3);
-                                    const double tmp9 = w20*(D_0 + D_2);
-                                    const double tmp10 = w22*(D_0 + D_3);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=D_0*w23 + D_3*w24 + tmp5;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0 + tmp1;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp2;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0 + tmp1;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=D_1*w23 + D_2*w24 + tmp10;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp2;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp6 + tmp7;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp8 + tmp9;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp2;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=D_1*w24 + D_2*w23 + tmp10;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp3 + tmp4;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp2;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp6 + tmp7;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp3 + tmp4;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=D_0*w24 + D_3*w23 + tmp5;
-                                }
-                             }
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        if (y.actsExpanded()) {
+                            EM_F[0] = w8*y_p[0] + w9*y_p[1];
+                            EM_F[1] = w8*y_p[1] + w9*y_p[0];
                         } else { // constant data
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double D_0 = D_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=16*D_0*w22;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=4*D_0*w22;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=16*D_0*w22;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=4*D_0*w22;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=4*D_0*w22;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=16*D_0*w22;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=4*D_0*w22;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=8*D_0*w22;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=16*D_0*w22;
-                                }
-                            }
+                            EM_F[0] = 6*w5*y_p[0];
+                            EM_F[1] = 6*w5*y_p[0];
                         }
                     }
+                    const index_t firstNode=k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
+                }
+            } // end colouring
+        }
+
+        if (domain->m_faceOffset[3] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[0] = 0;
+                EM_F[1] = 0;
+            }
+
+            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
+#pragma omp for
+                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
+                    const index_t e = domain->m_faceOffset[3]+k0;
                     ///////////////
-                    // process X //
+                    // process d //
                     ///////////////
-                    if (!X.isEmpty()) {
-                        addEM_F=true;
-                        const double* X_p=X.getSampleDataRO(e);
-                        if (X.actsExpanded()) {
-                            for (index_t k=0; k<numEq; k++) {
-                                const double X_0_0 = X_p[INDEX3(k,0,0,numEq,2)];
-                                const double X_1_0 = X_p[INDEX3(k,1,0,numEq,2)];
-                                const double X_0_1 = X_p[INDEX3(k,0,1,numEq,2)];
-                                const double X_1_1 = X_p[INDEX3(k,1,1,numEq,2)];
-                                const double X_0_2 = X_p[INDEX3(k,0,2,numEq,2)];
-                                const double X_1_2 = X_p[INDEX3(k,1,2,numEq,2)];
-                                const double X_0_3 = X_p[INDEX3(k,0,3,numEq,2)];
-                                const double X_1_3 = X_p[INDEX3(k,1,3,numEq,2)];
-                                const double tmp0 = 6*w15*(X_0_2 + X_0_3);
-                                const double tmp1 = 6*w10*(X_0_0 + X_0_1);
-                                const double tmp2 = 6*w11*(X_1_0 + X_1_2);
-                                const double tmp3 = 6*w14*(X_1_1 + X_1_3);
-                                const double tmp4 = 6*w11*(X_1_1 + X_1_3);
-                                const double tmp5 = w25*(X_0_0 + X_0_1);
-                                const double tmp6 = w26*(X_0_2 + X_0_3);
-                                const double tmp7 = 6*w14*(X_1_0 + X_1_2);
-                                const double tmp8 = w27*(X_1_0 + X_1_2);
-                                const double tmp9 = w28*(X_1_1 + X_1_3);
-                                const double tmp10 = w25*(-X_0_2 - X_0_3);
-                                const double tmp11 = w26*(-X_0_0 - X_0_1);
-                                const double tmp12 = w27*(X_1_1 + X_1_3);
-                                const double tmp13 = w28*(X_1_0 + X_1_2);
-                                const double tmp14 = w25*(X_0_2 + X_0_3);
-                                const double tmp15 = w26*(X_0_0 + X_0_1);
-                                EM_F[INDEX2(k,0,numEq)]+=tmp0 + tmp1 + tmp2 + tmp3;
-                                EM_F[INDEX2(k,1,numEq)]+=tmp4 + tmp5 + tmp6 + tmp7;
-                                EM_F[INDEX2(k,2,numEq)]+=tmp10 + tmp11 + tmp8 + tmp9;
-                                EM_F[INDEX2(k,3,numEq)]+=tmp12 + tmp13 + tmp14 + tmp15;
-                            }
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        if (d.actsExpanded()) {
+                            const double d_0 = d_p[0];
+                            const double d_1 = d_p[1];
+                            const double tmp0 = w5*(d_0 + d_1);
+                            EM_S[INDEX2(2,2,4)] = d_0*w6 + d_1*w7;
+                            EM_S[INDEX2(3,2,4)] = tmp0;
+                            EM_S[INDEX2(2,3,4)] = tmp0;
+                            EM_S[INDEX2(3,3,4)] = d_0*w7 + d_1*w6;
                         } else { // constant data
-                            for (index_t k=0; k<numEq; k++) {
-                                const double wX0 = X_p[INDEX2(k, 0, numEq)]*w18;
-                                const double wX1 = X_p[INDEX2(k, 1, numEq)]*w19;
-                                EM_F[INDEX2(k,0,numEq)]+= 6*wX0 + 6*wX1;
-                                EM_F[INDEX2(k,1,numEq)]+=-6*wX0 + 6*wX1;
-                                EM_F[INDEX2(k,2,numEq)]+= 6*wX0 - 6*wX1;
-                                EM_F[INDEX2(k,3,numEq)]+=-6*wX0 - 6*wX1;
-                            }
+                            EM_S[INDEX2(2,2,4)] = 4*d_p[0]*w5;
+                            EM_S[INDEX2(3,2,4)] = 2*d_p[0]*w5;
+                            EM_S[INDEX2(2,3,4)] = 2*d_p[0]*w5;
+                            EM_S[INDEX2(3,3,4)] = 4*d_p[0]*w5;
                         }
                     }
                     ///////////////
-                    // process Y //
+                    // process y //
                     ///////////////
-                    if (!Y.isEmpty()) {
-                        addEM_F=true;
-                        const double* Y_p=Y.getSampleDataRO(e);
-                        if (Y.actsExpanded()) {
-                            for (index_t k=0; k<numEq; k++) {
-                                const double Y_0 = Y_p[INDEX2(k, 0, numEq)];
-                                const double Y_1 = Y_p[INDEX2(k, 1, numEq)];
-                                const double Y_2 = Y_p[INDEX2(k, 2, numEq)];
-                                const double Y_3 = Y_p[INDEX2(k, 3, numEq)];
-                                const double tmp0 = 6*w22*(Y_1 + Y_2);
-                                const double tmp1 = 6*w22*(Y_0 + Y_3);
-                                EM_F[INDEX2(k,0,numEq)]+=6*Y_0*w20 + 6*Y_3*w21 + tmp0;
-                                EM_F[INDEX2(k,1,numEq)]+=6*Y_1*w20 + 6*Y_2*w21 + tmp1;
-                                EM_F[INDEX2(k,2,numEq)]+=6*Y_1*w21 + 6*Y_2*w20 + tmp1;
-                                EM_F[INDEX2(k,3,numEq)]+=6*Y_0*w21 + 6*Y_3*w20 + tmp0;
-                            }
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        if (y.actsExpanded()) {
+                            EM_F[2] = w8*y_p[0] + w9*y_p[1];
+                            EM_F[3] = w8*y_p[1] + w9*y_p[0];
                         } else { // constant data
-                            for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=36*Y_p[k]*w22;
-                                EM_F[INDEX2(k,1,numEq)]+=36*Y_p[k]*w22;
-                                EM_F[INDEX2(k,2,numEq)]+=36*Y_p[k]*w22;
-                                EM_F[INDEX2(k,3,numEq)]+=36*Y_p[k]*w22;
-                            }
+                            EM_F[2] = 6*w5*y_p[0];
+                            EM_F[3] = 6*w5*y_p[0];
                         }
                     }
-
-                    // add to matrix (if addEM_S) and RHS (if addEM_F)
-                    const index_t firstNode=m_NN[0]*k1+k0;
+                    const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
                     domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
-                            addEM_F, firstNode, numEq, numComp);
-                } // end k0 loop
-            } // end k1 loop
-        } // end of colouring
-    } // end of parallel region
+                                              addEM_F, firstNode);
+                }
+            } // end colouring
+        }
+    } // end of parallel section
 }
 
-void DefaultAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+/****************************************************************************/
+// PDE SINGLE REDUCED
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
                                     Data& rhs, const Data& A, const Data& B,
                                     const Data& C, const Data& D,
                                     const Data& X, const Data& Y) const
 {
-    dim_t numEq, numComp;
-    if (!mat)
-        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
-    else {
-        numEq=mat->getRowBlockSize();
-        numComp=mat->getColumnBlockSize();
-    }
-
     const double w0 = 1./4;
     const double w1 = m_dx[0]/8;
     const double w2 = m_dx[1]/8;
@@ -636,521 +832,826 @@ void DefaultAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
     const double w5 = m_dx[1]/(4*m_dx[0]);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
+    const bool addEM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool addEM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4, 0);
+        vector<double> EM_F(4, 0);
+
         for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
             for (index_t k1=k1_0; k1<NE1; k1+=2) {
                 for (index_t k0=0; k0<NE0; ++k0)  {
-                    bool addEM_S=false;
-                    bool addEM_F=false;
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = k0 + NE0*k1;
+                    if (addEM_S)
+                        fill(EM_S.begin(), EM_S.end(), 0);
+                    if (addEM_F)
+                        fill(EM_F.begin(), EM_F.end(), 0);
                     ///////////////
                     // process A //
                     ///////////////
                     if (!A.isEmpty()) {
-                        addEM_S=true;
                         const double* A_p=A.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double Aw00 = A_p[INDEX4(k,0,m,0, numEq,2, numComp)]*w5;
-                                const double Aw01 = A_p[INDEX4(k,0,m,1, numEq,2, numComp)]*w0;
-                                const double Aw10 = A_p[INDEX4(k,1,m,0, numEq,2, numComp)]*w0;
-                                const double Aw11 = A_p[INDEX4(k,1,m,1, numEq,2, numComp)]*w4;
-                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+= Aw00 + Aw01 + Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-Aw00 - Aw01 + Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+= Aw00 + Aw01 - Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=-Aw00 - Aw01 - Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-Aw00 + Aw01 - Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+= Aw00 - Aw01 - Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=-Aw00 + Aw01 + Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+= Aw00 - Aw01 + Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+= Aw00 - Aw01 + Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=-Aw00 + Aw01 + Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+= Aw00 - Aw01 - Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-Aw00 + Aw01 - Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=-Aw00 - Aw01 - Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+= Aw00 + Aw01 - Aw10 - Aw11;
-                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-Aw00 - Aw01 + Aw10 + Aw11;
-                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+= Aw00 + Aw01 + Aw10 + Aw11;
-                            }
-                        }
+                        const double A_00 = A_p[INDEX2(0,0,2)];
+                        const double A_10 = A_p[INDEX2(1,0,2)];
+                        const double A_01 = A_p[INDEX2(0,1,2)];
+                        const double A_11 = A_p[INDEX2(1,1,2)];
+                        const double tmp0 = (A_01 + A_10)*w0;
+                        const double tmp1 = A_00*w5;
+                        const double tmp2 = A_01*w0;
+                        const double tmp3 = A_10*w0;
+                        const double tmp4 = A_11*w4;
+                        EM_S[INDEX2(0,0,4)]+=tmp4 + tmp0 + tmp1;
+                        EM_S[INDEX2(1,0,4)]+=tmp4 - tmp1 + tmp3 - tmp2;
+                        EM_S[INDEX2(2,0,4)]+=tmp2 - tmp3 - tmp4 + tmp1;
+                        EM_S[INDEX2(3,0,4)]+=-tmp1 - tmp4 - tmp0;
+                        EM_S[INDEX2(0,1,4)]+=tmp4 - tmp1 + tmp2 - tmp3;
+                        EM_S[INDEX2(1,1,4)]+=tmp4 + tmp1 - tmp0;
+                        EM_S[INDEX2(2,1,4)]+=-tmp1 + tmp0 - tmp4;
+                        EM_S[INDEX2(3,1,4)]+=-tmp4 + tmp1 + tmp3 - tmp2;
+                        EM_S[INDEX2(0,2,4)]+=-tmp4 + tmp1 + tmp3 - tmp2;
+                        EM_S[INDEX2(1,2,4)]+=-tmp1 + tmp0 - tmp4;
+                        EM_S[INDEX2(2,2,4)]+=tmp4 + tmp1 - tmp0;
+                        EM_S[INDEX2(3,2,4)]+=tmp4 - tmp1 + tmp2 - tmp3;
+                        EM_S[INDEX2(0,3,4)]+=-tmp1 - tmp4 - tmp0;
+                        EM_S[INDEX2(1,3,4)]+=tmp2 - tmp3 - tmp4 + tmp1;
+                        EM_S[INDEX2(2,3,4)]+=tmp4 - tmp1 + tmp3 - tmp2;
+                        EM_S[INDEX2(3,3,4)]+=tmp4 + tmp0 + tmp1;
                     }
                     ///////////////
                     // process B //
                     ///////////////
                     if (!B.isEmpty()) {
-                        addEM_S=true;
                         const double* B_p=B.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double wB0 = B_p[INDEX3(k,0,m, numEq, 2)]*w2;
-                                const double wB1 = B_p[INDEX3(k,1,m, numEq, 2)]*w1;
-                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=-wB0 - wB1;
-                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-wB0 - wB1;
-                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-wB0 - wB1;
-                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=-wB0 - wB1;
-                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+= wB0 - wB1;
-                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+= wB0 - wB1;
-                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+= wB0 - wB1;
-                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+= wB0 - wB1;
-                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-wB0 + wB1;
-                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=-wB0 + wB1;
-                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=-wB0 + wB1;
-                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-wB0 + wB1;
-                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+= wB0 + wB1;
-                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+= wB0 + wB1;
-                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+= wB0 + wB1;
-                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+= wB0 + wB1;
-                            }
-                        }
+                        const double tmp0 = B_p[0]*w2;
+                        const double tmp1 = B_p[1]*w1;
+                        EM_S[INDEX2(0,0,4)]+=-tmp0 - tmp1;
+                        EM_S[INDEX2(1,0,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(2,0,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(3,0,4)]+= tmp0 + tmp1;
+                        EM_S[INDEX2(0,1,4)]+=-tmp0 - tmp1;
+                        EM_S[INDEX2(1,1,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(2,1,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(3,1,4)]+= tmp0 + tmp1;
+                        EM_S[INDEX2(0,2,4)]+=-tmp0 - tmp1;
+                        EM_S[INDEX2(1,2,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(2,2,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(3,2,4)]+= tmp0 + tmp1;
+                        EM_S[INDEX2(0,3,4)]+=-tmp0 - tmp1;
+                        EM_S[INDEX2(1,3,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(2,3,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(3,3,4)]+= tmp0 + tmp1;
                     }
                     ///////////////
                     // process C //
                     ///////////////
                     if (!C.isEmpty()) {
-                        addEM_S=true;
                         const double* C_p=C.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double wC0 = C_p[INDEX3(k, m, 0, numEq, numComp)]*w2;
-                                const double wC1 = C_p[INDEX3(k, m, 1, numEq, numComp)]*w1;
-                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=-wC0 - wC1;
-                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-wC0 - wC1;
-                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-wC0 - wC1;
-                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=-wC0 - wC1;
-                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+= wC0 - wC1;
-                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+= wC0 - wC1;
-                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+= wC0 - wC1;
-                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+= wC0 - wC1;
-                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-wC0 + wC1;
-                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=-wC0 + wC1;
-                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=-wC0 + wC1;
-                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-wC0 + wC1;
-                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+= wC0 + wC1;
-                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+= wC0 + wC1;
-                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+= wC0 + wC1;
-                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+= wC0 + wC1;
-                            }
-                        }
+                        const double tmp0 = C_p[0]*w2;
+                        const double tmp1 = C_p[1]*w1;
+                        EM_S[INDEX2(0,0,4)]+=-tmp1 - tmp0;
+                        EM_S[INDEX2(1,0,4)]+=-tmp1 - tmp0;
+                        EM_S[INDEX2(2,0,4)]+=-tmp1 - tmp0;
+                        EM_S[INDEX2(3,0,4)]+=-tmp1 - tmp0;
+                        EM_S[INDEX2(0,1,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(1,1,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(2,1,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(3,1,4)]+= tmp0 - tmp1;
+                        EM_S[INDEX2(0,2,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(1,2,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(2,2,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(3,2,4)]+= tmp1 - tmp0;
+                        EM_S[INDEX2(0,3,4)]+= tmp0 + tmp1;
+                        EM_S[INDEX2(1,3,4)]+= tmp0 + tmp1;
+                        EM_S[INDEX2(2,3,4)]+= tmp0 + tmp1;
+                        EM_S[INDEX2(3,3,4)]+= tmp0 + tmp1;
                     }
                     ///////////////
                     // process D //
                     ///////////////
                     if (!D.isEmpty()) {
-                        addEM_S=true;
                         const double* D_p=D.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double wD0 = D_p[INDEX2(k, m, numEq)]*w3;
-                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=wD0;
-                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=wD0;
-                            }
-                        }
+                        EM_S[INDEX2(0,0,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(1,0,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(2,0,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(3,0,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(0,1,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(1,1,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(2,1,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(3,1,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(0,2,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(1,2,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(2,2,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(3,2,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(0,3,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(1,3,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(2,3,4)]+=D_p[0]*w3;
+                        EM_S[INDEX2(3,3,4)]+=D_p[0]*w3;
                     }
                     ///////////////
                     // process X //
                     ///////////////
                     if (!X.isEmpty()) {
-                        addEM_F=true;
                         const double* X_p=X.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            const double wX0 = 4*X_p[INDEX2(k, 0, numEq)]*w2;
-                            const double wX1 = 4*X_p[INDEX2(k, 1, numEq)]*w1;
-                            EM_F[INDEX2(k,0,numEq)]+=-wX0 - wX1;
-                            EM_F[INDEX2(k,1,numEq)]+= wX0 - wX1;
-                            EM_F[INDEX2(k,2,numEq)]+=-wX0 + wX1;
-                            EM_F[INDEX2(k,3,numEq)]+= wX0 + wX1;
-                        }
+                        const double wX0 = 4*X_p[0]*w2;
+                        const double wX1 = 4*X_p[1]*w1;
+                        EM_F[0]+=-wX0 - wX1;
+                        EM_F[1]+=-wX1 + wX0;
+                        EM_F[2]+=-wX0 + wX1;
+                        EM_F[3]+= wX0 + wX1;
                     }
                     ///////////////
                     // process Y //
                     ///////////////
                     if (!Y.isEmpty()) {
-                        addEM_F=true;
                         const double* Y_p=Y.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            EM_F[INDEX2(k,0,numEq)]+=4*Y_p[k]*w3;
-                            EM_F[INDEX2(k,1,numEq)]+=4*Y_p[k]*w3;
-                            EM_F[INDEX2(k,2,numEq)]+=4*Y_p[k]*w3;
-                            EM_F[INDEX2(k,3,numEq)]+=4*Y_p[k]*w3;
-                        }
+                        EM_F[0]+=4*Y_p[0]*w3;
+                        EM_F[1]+=4*Y_p[0]*w3;
+                        EM_F[2]+=4*Y_p[0]*w3;
+                        EM_F[3]+=4*Y_p[0]*w3;
                     }
 
                     // add to matrix (if addEM_S) and RHS (if addEM_F)
                     const index_t firstNode=m_NN[0]*k1+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
                 } // end k0 loop
             } // end k1 loop
         } // end of colouring
     } // end of parallel region
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
-                                Data& rhs, const Data& d, const Data& y) const
+/****************************************************************************/
+// PDE SINGLE REDUCED BOUNDARY
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDEBoundarySingleReduced(
+                                        AbstractSystemMatrix* mat, Data& rhs,
+                                        const Data& d, const Data& y) const
 {
-    const double SQRT3 = 1.73205080756887719318;
-    const double w5 = m_dx[0]/12;
-    const double w6 = w5*(SQRT3 + 2);
-    const double w7 = w5*(-SQRT3 + 2);
-    const double w8 = w5*(SQRT3 + 3);
-    const double w9 = w5*(-SQRT3 + 3);
-    const double w2 = m_dx[1]/12;
-    const double w0 = w2*(SQRT3 + 2);
-    const double w1 = w2*(-SQRT3 + 2);
-    const double w3 = w2*(SQRT3 + 3);
-    const double w4 = w2*(-SQRT3 + 3);
-    const bool addEM_S=!d.isEmpty();
-    const bool addEM_F=!y.isEmpty();
+    const double w0 = m_dx[0]/4;
+    const double w1 = m_dx[1]/4;
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
+    const bool addEM_S = !d.isEmpty();
+    const bool addEM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4, 0);
+        vector<double> EM_F(4, 0);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[1] = 0;
+                EM_F[3] = 0;
+            }
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
                     ///////////////
                     // process d //
                     ///////////////
                     if (addEM_S) {
                         const double* d_p=d.getSampleDataRO(k1);
-                        if (d.actsExpanded()) {
-                            const double d_0 = d_p[0];
-                            const double d_1 = d_p[1];
-                            const double tmp0 = w2*(d_0 + d_1);
-                            EM_S[INDEX2(0,0,4)]+=d_0*w0 + d_1*w1;
-                            EM_S[INDEX2(2,0,4)]+=tmp0;
-                            EM_S[INDEX2(0,2,4)]+=tmp0;
-                            EM_S[INDEX2(2,2,4)]+=d_0*w1 + d_1*w0;
-                        } else { // constant data
-                            EM_S[INDEX2(0,0,4)]+=4*d_p[0]*w2;
-                            EM_S[INDEX2(2,0,4)]+=2*d_p[0]*w2;
-                            EM_S[INDEX2(0,2,4)]+=2*d_p[0]*w2;
-                            EM_S[INDEX2(2,2,4)]+=4*d_p[0]*w2;
-                        }
+                        EM_S[INDEX2(0,0,4)] = d_p[0]*w1;
+                        EM_S[INDEX2(2,0,4)] = d_p[0]*w1;
+                        EM_S[INDEX2(0,2,4)] = d_p[0]*w1;
+                        EM_S[INDEX2(2,2,4)] = d_p[0]*w1;
                     }
                     ///////////////
                     // process y //
                     ///////////////
                     if (addEM_F) {
                         const double* y_p=y.getSampleDataRO(k1);
-                        if (y.actsExpanded()) {
-                            EM_F[0]+=w3*y_p[0] + w4*y_p[1];
-                            EM_F[2]+=w3*y_p[1] + w4*y_p[0];
-                        } else { // constant data
-                            EM_F[0]+=6*w2*y_p[0];
-                            EM_F[2]+=6*w2*y_p[0];
-                        }
+                        EM_F[0] = 2*w1*y_p[0];
+                        EM_F[2] = 2*w1*y_p[0];
                     }
                     const index_t firstNode=m_NN[0]*k1;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
+                }
+            } // end colouring
+        }
+
+        if (domain->m_faceOffset[1] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[0] = 0;
+                EM_F[2] = 0;
+            }
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    const index_t e = domain->m_faceOffset[1]+k1;
+                    ///////////////
+                    // process d //
+                    ///////////////
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        EM_S[INDEX2(1,1,4)] = d_p[0]*w1;
+                        EM_S[INDEX2(3,1,4)] = d_p[0]*w1;
+                        EM_S[INDEX2(1,3,4)] = d_p[0]*w1;
+                        EM_S[INDEX2(3,3,4)] = d_p[0]*w1;
+                    }
+                    ///////////////
+                    // process y //
+                    ///////////////
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        EM_F[1] = 2*w1*y_p[0];
+                        EM_F[3] = 2*w1*y_p[0];
+                    }
+                    const index_t firstNode=m_NN[0]*(k1+1)-2;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
                 }
             } // end colouring
         }
 
-        if (domain->m_faceOffset[1] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
+        if (domain->m_faceOffset[2] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[2] = 0;
+                EM_F[3] = 0;
+            }
+
+            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
 #pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    const index_t e = domain->m_faceOffset[1]+k1;
+                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
+                    const index_t e = domain->m_faceOffset[2]+k0;
                     ///////////////
                     // process d //
                     ///////////////
                     if (addEM_S) {
                         const double* d_p=d.getSampleDataRO(e);
-                        if (d.actsExpanded()) {
-                            const double d_0 = d_p[0];
-                            const double d_1 = d_p[1];
-                            const double tmp0 = w2*(d_0 + d_1);
-                            EM_S[INDEX2(1,1,4)]+=d_0*w0 + d_1*w1;
-                            EM_S[INDEX2(3,1,4)]+=tmp0;
-                            EM_S[INDEX2(1,3,4)]+=tmp0;
-                            EM_S[INDEX2(3,3,4)]+=d_0*w1 + d_1*w0;
-                        } else { // constant data
-                            EM_S[INDEX2(1,1,4)]+=4*d_p[0]*w2;
-                            EM_S[INDEX2(3,1,4)]+=2*d_p[0]*w2;
-                            EM_S[INDEX2(1,3,4)]+=2*d_p[0]*w2;
-                            EM_S[INDEX2(3,3,4)]+=4*d_p[0]*w2;
-                        }
+                        EM_S[INDEX2(0,0,4)] = d_p[0]*w0;
+                        EM_S[INDEX2(1,0,4)] = d_p[0]*w0;
+                        EM_S[INDEX2(0,1,4)] = d_p[0]*w0;
+                        EM_S[INDEX2(1,1,4)] = d_p[0]*w0;
                     }
                     ///////////////
                     // process y //
                     ///////////////
                     if (addEM_F) {
                         const double* y_p=y.getSampleDataRO(e);
-                        if (y.actsExpanded()) {
-                            EM_F[1]+=w3*y_p[0] + w4*y_p[1];
-                            EM_F[3]+=w3*y_p[1] + w4*y_p[0];
-                        } else { // constant data
-                            EM_F[1]+=6*w2*y_p[0];
-                            EM_F[3]+=6*w2*y_p[0];
-                        }
+                        EM_F[0] = 2*w0*y_p[0];
+                        EM_F[1] = 2*w0*y_p[0];
                     }
-                    const index_t firstNode=m_NN[0]*(k1+1)-2;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
+                    const index_t firstNode=k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
                 }
             } // end colouring
         }
 
-        if (domain->m_faceOffset[2] > -1) {
+        if (domain->m_faceOffset[3] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F) {
+                EM_F[0] = 0;
+                EM_F[1] = 0;
+            }
+
             for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
 #pragma omp for
                 for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    const index_t e = domain->m_faceOffset[2]+k0;
+                    const index_t e = domain->m_faceOffset[3]+k0;
                     ///////////////
                     // process d //
                     ///////////////
                     if (addEM_S) {
                         const double* d_p=d.getSampleDataRO(e);
-                        if (d.actsExpanded()) {
-                            const double d_0 = d_p[0];
-                            const double d_1 = d_p[1];
-                            const double tmp0 = w5*(d_0 + d_1);
-                            EM_S[INDEX2(0,0,4)]+=d_0*w6 + d_1*w7;
-                            EM_S[INDEX2(1,0,4)]+=tmp0;
-                            EM_S[INDEX2(0,1,4)]+=tmp0;
-                            EM_S[INDEX2(1,1,4)]+=d_0*w7 + d_1*w6;
-                        } else { // constant data
-                            EM_S[INDEX2(0,0,4)]+=4*d_p[0]*w5;
-                            EM_S[INDEX2(1,0,4)]+=2*d_p[0]*w5;
-                            EM_S[INDEX2(0,1,4)]+=2*d_p[0]*w5;
-                            EM_S[INDEX2(1,1,4)]+=4*d_p[0]*w5;
-                        }
+                        EM_S[INDEX2(2,2,4)] = d_p[0]*w0;
+                        EM_S[INDEX2(3,2,4)] = d_p[0]*w0;
+                        EM_S[INDEX2(2,3,4)] = d_p[0]*w0;
+                        EM_S[INDEX2(3,3,4)] = d_p[0]*w0;
                     }
                     ///////////////
                     // process y //
                     ///////////////
                     if (addEM_F) {
                         const double* y_p=y.getSampleDataRO(e);
-                        if (y.actsExpanded()) {
-                            EM_F[0]+=w8*y_p[0] + w9*y_p[1];
-                            EM_F[1]+=w8*y_p[1] + w9*y_p[0];
+                        EM_F[2] = 2*w0*y_p[0];
+                        EM_F[3] = 2*w0*y_p[0];
+                    }
+                    const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                              addEM_F, firstNode);
+                }
+            } // end colouring
+        }
+    } // end of parallel section
+}
+
+/****************************************************************************/
+// PDE SYSTEM
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
+                                     Data& rhs, const Data& A, const Data& B,
+                                     const Data& C, const Data& D,
+                                     const Data& X, const Data& Y) const
+{
+    dim_t numEq, numComp;
+    if (!mat)
+        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
+    else {
+        numEq=mat->getRowBlockSize();
+        numComp=mat->getColumnBlockSize();
+    }
+    const double SQRT3 = 1.73205080756887719318;
+    const double w1 = 1.0/24;
+    const double w5 = -SQRT3/24 + 1.0/12;
+    const double w2 = -SQRT3/24 - 1.0/12;
+    const double w19 = -m_dx[0]/12;
+    const double w11 = w19*(SQRT3 + 3)/12;
+    const double w14 = w19*(-SQRT3 + 3)/12;
+    const double w16 = w19*(5*SQRT3 + 9)/12;
+    const double w17 = w19*(-5*SQRT3 + 9)/12;
+    const double w27 = w19*(-SQRT3 - 3)/2;
+    const double w28 = w19*(SQRT3 - 3)/2;
+    const double w18 = -m_dx[1]/12;
+    const double w10 = w18*(SQRT3 + 3)/12;
+    const double w15 = w18*(-SQRT3 + 3)/12;
+    const double w12 = w18*(5*SQRT3 + 9)/12;
+    const double w13 = w18*(-5*SQRT3 + 9)/12;
+    const double w25 = w18*(-SQRT3 - 3)/2;
+    const double w26 = w18*(SQRT3 - 3)/2;
+    const double w22 = m_dx[0]*m_dx[1]/144;
+    const double w20 = w22*(SQRT3 + 2);
+    const double w21 = w22*(-SQRT3 + 2);
+    const double w23 = w22*(4*SQRT3 + 7);
+    const double w24 = w22*(-4*SQRT3 + 7);
+    const double w3 = m_dx[0]/(24*m_dx[1]);
+    const double w7 = w3*(SQRT3 + 2);
+    const double w8 = w3*(-SQRT3 + 2);
+    const double w6 = -m_dx[1]/(24*m_dx[0]);
+    const double w0 = w6*(SQRT3 + 2);
+    const double w4 = w6*(-SQRT3 + 2);
+    const int NE0 = m_NE[0];
+    const int NE1 = m_NE[1];
+    const bool addEM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool addEM_F = (!X.isEmpty() || !Y.isEmpty());
+    rhs.requireWrite();
+
+#pragma omp parallel
+    {
+        vector<double> EM_S(4*4*numEq*numComp, 0);
+        vector<double> EM_F(4*numEq, 0);
+
+        for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
+#pragma omp for
+            for (index_t k1=k1_0; k1 < NE1; k1+=2) {
+                for (index_t k0=0; k0 < NE0; ++k0)  {
+                    const index_t e = k0 + NE0*k1;
+                    if (addEM_S)
+                        fill(EM_S.begin(), EM_S.end(), 0);
+                    if (addEM_F)
+                        fill(EM_F.begin(), EM_F.end(), 0);
+                    ///////////////
+                    // process A //
+                    ///////////////
+                    if (!A.isEmpty()) {
+                        const double* A_p = A.getSampleDataRO(e);
+                        if (A.actsExpanded()) {
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double A_00_0 = A_p[INDEX5(k,0,m,0,0,numEq,2,numComp,2)];
+                                    const double A_01_0 = A_p[INDEX5(k,0,m,1,0,numEq,2,numComp,2)];
+                                    const double A_10_0 = A_p[INDEX5(k,1,m,0,0,numEq,2,numComp,2)];
+                                    const double A_11_0 = A_p[INDEX5(k,1,m,1,0,numEq,2,numComp,2)];
+                                    const double A_00_1 = A_p[INDEX5(k,0,m,0,1,numEq,2,numComp,2)];
+                                    const double A_01_1 = A_p[INDEX5(k,0,m,1,1,numEq,2,numComp,2)];
+                                    const double A_10_1 = A_p[INDEX5(k,1,m,0,1,numEq,2,numComp,2)];
+                                    const double A_11_1 = A_p[INDEX5(k,1,m,1,1,numEq,2,numComp,2)];
+                                    const double A_00_2 = A_p[INDEX5(k,0,m,0,2,numEq,2,numComp,2)];
+                                    const double A_01_2 = A_p[INDEX5(k,0,m,1,2,numEq,2,numComp,2)];
+                                    const double A_10_2 = A_p[INDEX5(k,1,m,0,2,numEq,2,numComp,2)];
+                                    const double A_11_2 = A_p[INDEX5(k,1,m,1,2,numEq,2,numComp,2)];
+                                    const double A_00_3 = A_p[INDEX5(k,0,m,0,3,numEq,2,numComp,2)];
+                                    const double A_01_3 = A_p[INDEX5(k,0,m,1,3,numEq,2,numComp,2)];
+                                    const double A_10_3 = A_p[INDEX5(k,1,m,0,3,numEq,2,numComp,2)];
+                                    const double A_11_3 = A_p[INDEX5(k,1,m,1,3,numEq,2,numComp,2)];
+                                    const double tmp0 = w3*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
+                                    const double tmp1 = w1*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
+                                    const double tmp2 = w4*(A_00_2 + A_00_3);
+                                    const double tmp3 = w0*(A_00_0 + A_00_1);
+                                    const double tmp4 = w5*(A_01_2 - A_10_3);
+                                    const double tmp5 = w2*(-A_01_1 + A_10_0);
+                                    const double tmp6 = w5*(A_01_3 + A_10_0);
+                                    const double tmp7 = w3*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
+                                    const double tmp8 = w6*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
+                                    const double tmp9 = w1*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
+                                    const double tmp10 = w2*(-A_01_0 - A_10_3);
+                                    const double tmp11 = w4*(A_00_0 + A_00_1);
+                                    const double tmp12 = w0*(A_00_2 + A_00_3);
+                                    const double tmp13 = w5*(A_01_1 - A_10_0);
+                                    const double tmp14 = w2*(-A_01_2 + A_10_3);
+                                    const double tmp15 = w7*(A_11_0 + A_11_2);
+                                    const double tmp16 = w4*(-A_00_2 - A_00_3);
+                                    const double tmp17 = w0*(-A_00_0 - A_00_1);
+                                    const double tmp18 = w5*(A_01_3 + A_10_3);
+                                    const double tmp19 = w8*(A_11_1 + A_11_3);
+                                    const double tmp20 = w2*(-A_01_0 - A_10_0);
+                                    const double tmp21 = w7*(A_11_1 + A_11_3);
+                                    const double tmp22 = w4*(-A_00_0 - A_00_1);
+                                    const double tmp23 = w0*(-A_00_2 - A_00_3);
+                                    const double tmp24 = w5*(A_01_0 + A_10_0);
+                                    const double tmp25 = w8*(A_11_0 + A_11_2);
+                                    const double tmp26 = w2*(-A_01_3 - A_10_3);
+                                    const double tmp27 = w5*(-A_01_1 - A_10_2);
+                                    const double tmp28 = w1*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
+                                    const double tmp29 = w2*(A_01_2 + A_10_1);
+                                    const double tmp30 = w7*(-A_11_1 - A_11_3);
+                                    const double tmp31 = w1*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
+                                    const double tmp32 = w5*(-A_01_0 + A_10_2);
+                                    const double tmp33 = w8*(-A_11_0 - A_11_2);
+                                    const double tmp34 = w6*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
+                                    const double tmp35 = w2*(A_01_3 - A_10_1);
+                                    const double tmp36 = w5*(A_01_0 + A_10_3);
+                                    const double tmp37 = w2*(-A_01_3 - A_10_0);
+                                    const double tmp38 = w7*(-A_11_0 - A_11_2);
+                                    const double tmp39 = w5*(-A_01_3 + A_10_1);
+                                    const double tmp40 = w8*(-A_11_1 - A_11_3);
+                                    const double tmp41 = w2*(A_01_0 - A_10_2);
+                                    const double tmp42 = w5*(A_01_1 - A_10_3);
+                                    const double tmp43 = w2*(-A_01_2 + A_10_0);
+                                    const double tmp44 = w5*(A_01_2 - A_10_0);
+                                    const double tmp45 = w2*(-A_01_1 + A_10_3);
+                                    const double tmp46 = w5*(-A_01_0 + A_10_1);
+                                    const double tmp47 = w2*(A_01_3 - A_10_2);
+                                    const double tmp48 = w5*(-A_01_1 - A_10_1);
+                                    const double tmp49 = w2*(A_01_2 + A_10_2);
+                                    const double tmp50 = w5*(-A_01_3 + A_10_2);
+                                    const double tmp51 = w2*(A_01_0 - A_10_1);
+                                    const double tmp52 = w5*(-A_01_2 - A_10_1);
+                                    const double tmp53 = w2*(A_01_1 + A_10_2);
+                                    const double tmp54 = w5*(-A_01_2 - A_10_2);
+                                    const double tmp55 = w2*(A_01_1 + A_10_1);
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp20 + tmp9;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp31 + tmp34 + tmp38 + tmp39 + tmp40 + tmp41;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp28 + tmp52 + tmp53 + tmp7 + tmp8;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0 + tmp2 + tmp3 + tmp31 + tmp50 + tmp51;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=tmp16 + tmp17 + tmp21 + tmp25 + tmp28 + tmp54 + tmp55;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp10 + tmp6 + tmp7 + tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp1 + tmp30 + tmp33 + tmp34 + tmp44 + tmp45;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp1 + tmp34 + tmp38 + tmp40 + tmp42 + tmp43;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp36 + tmp37 + tmp7 + tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=tmp15 + tmp19 + tmp22 + tmp23 + tmp28 + tmp48 + tmp49;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp0 + tmp11 + tmp12 + tmp31 + tmp46 + tmp47;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp27 + tmp28 + tmp29 + tmp7 + tmp8;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp0 + tmp1 + tmp11 + tmp12 + tmp13 + tmp14;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp9;
+                                }
+                            }
+                        } else { // constant data
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double A_00 = A_p[INDEX4(k,0,m,0, numEq,2, numComp)];
+                                    const double A_01 = A_p[INDEX4(k,0,m,1, numEq,2, numComp)];
+                                    const double A_10 = A_p[INDEX4(k,1,m,0, numEq,2, numComp)];
+                                    const double A_11 = A_p[INDEX4(k,1,m,1, numEq,2, numComp)];
+                                    const double tmp0 = 6*w1*(A_01 - A_10);
+                                    const double tmp1 = 6*w1*(A_01 + A_10);
+                                    const double tmp2 = 6*w1*(-A_01 - A_10);
+                                    const double tmp3 = 6*w1*(-A_01 + A_10);
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
+                                }
+                            }
+                        }
+                    }
+                    ///////////////
+                    // process B //
+                    ///////////////
+                    if (!B.isEmpty()) {
+                        const double* B_p=B.getSampleDataRO(e);
+                        if (B.actsExpanded()) {
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double B_0_0 = B_p[INDEX4(k,0,m,0, numEq,2,numComp)];
+                                    const double B_1_0 = B_p[INDEX4(k,1,m,0, numEq,2,numComp)];
+                                    const double B_0_1 = B_p[INDEX4(k,0,m,1, numEq,2,numComp)];
+                                    const double B_1_1 = B_p[INDEX4(k,1,m,1, numEq,2,numComp)];
+                                    const double B_0_2 = B_p[INDEX4(k,0,m,2, numEq,2,numComp)];
+                                    const double B_1_2 = B_p[INDEX4(k,1,m,2, numEq,2,numComp)];
+                                    const double B_0_3 = B_p[INDEX4(k,0,m,3, numEq,2,numComp)];
+                                    const double B_1_3 = B_p[INDEX4(k,1,m,3, numEq,2,numComp)];
+                                    const double tmp0 = w11*(B_1_0 + B_1_1);
+                                    const double tmp1 = w14*(B_1_2 + B_1_3);
+                                    const double tmp2 = w15*(-B_0_1 - B_0_3);
+                                    const double tmp3 = w10*(-B_0_0 - B_0_2);
+                                    const double tmp4 = w11*(B_1_2 + B_1_3);
+                                    const double tmp5 = w14*(B_1_0 + B_1_1);
+                                    const double tmp6 = w11*(-B_1_2 - B_1_3);
+                                    const double tmp7 = w14*(-B_1_0 - B_1_1);
+                                    const double tmp8 = w11*(-B_1_0 - B_1_1);
+                                    const double tmp9 = w14*(-B_1_2 - B_1_3);
+                                    const double tmp10 = w10*(-B_0_1 - B_0_3);
+                                    const double tmp11 = w15*(-B_0_0 - B_0_2);
+                                    const double tmp12 = w15*(B_0_0 + B_0_2);
+                                    const double tmp13 = w10*(B_0_1 + B_0_3);
+                                    const double tmp14 = w10*(B_0_0 + B_0_2);
+                                    const double tmp15 = w15*(B_0_1 + B_0_3);
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=B_0_0*w12 + B_0_1*w10 + B_0_2*w15 + B_0_3*w13 + B_1_0*w16 + B_1_1*w14 + B_1_2*w11 + B_1_3*w17;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=B_0_0*w10 + B_0_1*w12 + B_0_2*w13 + B_0_3*w15 + tmp0 + tmp1;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=B_1_0*w11 + B_1_1*w17 + B_1_2*w16 + B_1_3*w14 + tmp14 + tmp15;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-B_0_0*w12 - B_0_1*w10 - B_0_2*w15 - B_0_3*w13 + tmp0 + tmp1;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-B_0_0*w10 - B_0_1*w12 - B_0_2*w13 - B_0_3*w15 + B_1_0*w14 + B_1_1*w16 + B_1_2*w17 + B_1_3*w11;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=B_1_0*w17 + B_1_1*w11 + B_1_2*w14 + B_1_3*w16 + tmp10 + tmp11;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-B_1_0*w16 - B_1_1*w14 - B_1_2*w11 - B_1_3*w17 + tmp14 + tmp15;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=B_0_0*w15 + B_0_1*w13 + B_0_2*w12 + B_0_3*w10 - B_1_0*w11 - B_1_1*w17 - B_1_2*w16 - B_1_3*w14;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=B_0_0*w13 + B_0_1*w15 + B_0_2*w10 + B_0_3*w12 + tmp6 + tmp7;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=-B_1_0*w14 - B_1_1*w16 - B_1_2*w17 - B_1_3*w11 + tmp10 + tmp11;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-B_0_0*w15 - B_0_1*w13 - B_0_2*w12 - B_0_3*w10 + tmp6 + tmp7;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-B_0_0*w13 - B_0_1*w15 - B_0_2*w10 - B_0_3*w12 - B_1_0*w17 - B_1_1*w11 - B_1_2*w14 - B_1_3*w16;
+                                }
+                            }
                         } else { // constant data
-                            EM_F[0]+=6*w5*y_p[0];
-                            EM_F[1]+=6*w5*y_p[0];
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double wB0 = B_p[INDEX3(k,0,m,numEq,2)]*w18;
+                                    const double wB1 = B_p[INDEX3(k,1,m,numEq,2)]*w19;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+= 2*wB0 + 2*wB1;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+= 2*wB0 +   wB1;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=   wB0 + 2*wB1;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=   wB0 +   wB1;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-2*wB0 +   wB1;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-2*wB0 + 2*wB1;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=  -wB0 +   wB1;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=  -wB0 + 2*wB1;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=   wB0 - 2*wB1;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=   wB0 -   wB1;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+= 2*wB0 - 2*wB1;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+= 2*wB0 -   wB1;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=  -wB0 -   wB1;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=  -wB0 - 2*wB1;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-2*wB0 -   wB1;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-2*wB0 - 2*wB1;
+                                }
+                            }
                         }
                     }
-                    const index_t firstNode=k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[3] > -1) {
-            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
-#pragma omp for
-                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    const index_t e = domain->m_faceOffset[3]+k0;
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
                     ///////////////
-                    // process d //
+                    // process C //
                     ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        if (d.actsExpanded()) {
-                            const double d_0 = d_p[0];
-                            const double d_1 = d_p[1];
-                            const double tmp0 = w5*(d_0 + d_1);
-                            EM_S[INDEX2(2,2,4)]+=d_0*w6 + d_1*w7;
-                            EM_S[INDEX2(3,2,4)]+=tmp0;
-                            EM_S[INDEX2(2,3,4)]+=tmp0;
-                            EM_S[INDEX2(3,3,4)]+=d_0*w7 + d_1*w6;
+                    if (!C.isEmpty()) {
+                        const double* C_p=C.getSampleDataRO(e);
+                        if (C.actsExpanded()) {
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double C_0_0 = C_p[INDEX4(k,m,0, 0, numEq,numComp,2)];
+                                    const double C_1_0 = C_p[INDEX4(k,m,1, 0, numEq,numComp,2)];
+                                    const double C_0_1 = C_p[INDEX4(k,m,0, 1, numEq,numComp,2)];
+                                    const double C_1_1 = C_p[INDEX4(k,m,1, 1, numEq,numComp,2)];
+                                    const double C_0_2 = C_p[INDEX4(k,m,0, 2, numEq,numComp,2)];
+                                    const double C_1_2 = C_p[INDEX4(k,m,1, 2, numEq,numComp,2)];
+                                    const double C_0_3 = C_p[INDEX4(k,m,0, 3, numEq,numComp,2)];
+                                    const double C_1_3 = C_p[INDEX4(k,m,1, 3, numEq,numComp,2)];
+                                    const double tmp0 = w11*(C_1_0 + C_1_1);
+                                    const double tmp1 = w14*(C_1_2 + C_1_3);
+                                    const double tmp2 = w15*(C_0_0 + C_0_2);
+                                    const double tmp3 = w10*(C_0_1 + C_0_3);
+                                    const double tmp4 = w11*(-C_1_0 - C_1_1);
+                                    const double tmp5 = w14*(-C_1_2 - C_1_3);
+                                    const double tmp6 = w11*(-C_1_2 - C_1_3);
+                                    const double tmp7 = w14*(-C_1_0 - C_1_1);
+                                    const double tmp8 = w11*(C_1_2 + C_1_3);
+                                    const double tmp9 = w14*(C_1_0 + C_1_1);
+                                    const double tmp10 = w10*(-C_0_1 - C_0_3);
+                                    const double tmp11 = w15*(-C_0_0 - C_0_2);
+                                    const double tmp12 = w15*(-C_0_1 - C_0_3);
+                                    const double tmp13 = w10*(-C_0_0 - C_0_2);
+                                    const double tmp14 = w10*(C_0_0 + C_0_2);
+                                    const double tmp15 = w15*(C_0_1 + C_0_3);
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=C_0_0*w12 + C_0_1*w10 + C_0_2*w15 + C_0_3*w13 + C_1_0*w16 + C_1_1*w14 + C_1_2*w11 + C_1_3*w17;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-C_0_0*w12 - C_0_1*w10 - C_0_2*w15 - C_0_3*w13 + tmp0 + tmp1;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-C_1_0*w16 - C_1_1*w14 - C_1_2*w11 - C_1_3*w17 + tmp14 + tmp15;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=C_0_0*w10 + C_0_1*w12 + C_0_2*w13 + C_0_3*w15 + tmp0 + tmp1;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-C_0_0*w10 - C_0_1*w12 - C_0_2*w13 - C_0_3*w15 + C_1_0*w14 + C_1_1*w16 + C_1_2*w17 + C_1_3*w11;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=-C_1_0*w14 - C_1_1*w16 - C_1_2*w17 - C_1_3*w11 + tmp10 + tmp11;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=C_1_0*w11 + C_1_1*w17 + C_1_2*w16 + C_1_3*w14 + tmp14 + tmp15;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=C_0_0*w15 + C_0_1*w13 + C_0_2*w12 + C_0_3*w10 - C_1_0*w11 - C_1_1*w17 - C_1_2*w16 - C_1_3*w14;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-C_0_0*w15 - C_0_1*w13 - C_0_2*w12 - C_0_3*w10 + tmp6 + tmp7;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=C_1_0*w17 + C_1_1*w11 + C_1_2*w14 + C_1_3*w16 + tmp10 + tmp11;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=C_0_0*w13 + C_0_1*w15 + C_0_2*w10 + C_0_3*w12 + tmp6 + tmp7;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-C_0_0*w13 - C_0_1*w15 - C_0_2*w10 - C_0_3*w12 - C_1_0*w17 - C_1_1*w11 - C_1_2*w14 - C_1_3*w16;
+                                }
+                            }
                         } else { // constant data
-                            EM_S[INDEX2(2,2,4)]+=4*d_p[0]*w5;
-                            EM_S[INDEX2(3,2,4)]+=2*d_p[0]*w5;
-                            EM_S[INDEX2(2,3,4)]+=2*d_p[0]*w5;
-                            EM_S[INDEX2(3,3,4)]+=4*d_p[0]*w5;
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double wC0 = C_p[INDEX3(k,m,0,numEq,numComp)]*w18;
+                                    const double wC1 = C_p[INDEX3(k,m,1,numEq,numComp)]*w19;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+= 2*wC0 + 2*wC1;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-2*wC0 +   wC1;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=   wC0 - 2*wC1;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=  -wC0 -   wC1;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+= 2*wC0 +   wC1;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=-2*wC0 + 2*wC1;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=   wC0 -   wC1;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=  -wC0 - 2*wC1;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=   wC0 + 2*wC1;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=  -wC0 +   wC1;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+= 2*wC0 - 2*wC1;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-2*wC0 -   wC1;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=   wC0 +   wC1;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=  -wC0 + 2*wC1;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+= 2*wC0 -   wC1;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=-2*wC0 - 2*wC1;
+                                }
+                            }
                         }
                     }
                     ///////////////
-                    // process y //
+                    // process D //
                     ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        if (y.actsExpanded()) {
-                            EM_F[2]+=w8*y_p[0] + w9*y_p[1];
-                            EM_F[3]+=w8*y_p[1] + w9*y_p[0];
+                    if (!D.isEmpty()) {
+                        const double* D_p=D.getSampleDataRO(e);
+                        if (D.actsExpanded()) {
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double D_0 = D_p[INDEX3(k,m,0,numEq,numComp)];
+                                    const double D_1 = D_p[INDEX3(k,m,1,numEq,numComp)];
+                                    const double D_2 = D_p[INDEX3(k,m,2,numEq,numComp)];
+                                    const double D_3 = D_p[INDEX3(k,m,3,numEq,numComp)];
+                                    const double tmp0 = w21*(D_2 + D_3);
+                                    const double tmp1 = w20*(D_0 + D_1);
+                                    const double tmp2 = w22*(D_0 + D_1 + D_2 + D_3);
+                                    const double tmp3 = w21*(D_0 + D_1);
+                                    const double tmp4 = w20*(D_2 + D_3);
+                                    const double tmp5 = w22*(D_1 + D_2);
+                                    const double tmp6 = w21*(D_0 + D_2);
+                                    const double tmp7 = w20*(D_1 + D_3);
+                                    const double tmp8 = w21*(D_1 + D_3);
+                                    const double tmp9 = w20*(D_0 + D_2);
+                                    const double tmp10 = w22*(D_0 + D_3);
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=D_0*w23 + D_3*w24 + tmp5;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0 + tmp1;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=tmp2;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0 + tmp1;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=D_1*w23 + D_2*w24 + tmp10;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=tmp2;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp6 + tmp7;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp8 + tmp9;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=tmp2;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=D_1*w24 + D_2*w23 + tmp10;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp3 + tmp4;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=tmp2;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp6 + tmp7;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp3 + tmp4;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=D_0*w24 + D_3*w23 + tmp5;
+                                }
+                             }
                         } else { // constant data
-                            EM_F[2]+=6*w5*y_p[0];
-                            EM_F[3]+=6*w5*y_p[0];
-                        }
-                    }
-                    const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                }
-            } // end colouring
-        }
-    } // end of parallel section
-}
-
-void DefaultAssembler2D::assemblePDEBoundarySingleReduced(
-                                        AbstractSystemMatrix* mat, Data& rhs,
-                                        const Data& d, const Data& y) const
-{
-    const double w0 = m_dx[0]/4;
-    const double w1 = m_dx[1]/4;
-    const bool addEM_S=!d.isEmpty();
-    const bool addEM_F=!y.isEmpty();
-    const int NE0 = m_NE[0];
-    const int NE1 = m_NE[1];
-    rhs.requireWrite();
-
-#pragma omp parallel
-    {
-        if (domain->m_faceOffset[0] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(k1);
-                        EM_S[INDEX2(0,0,4)]+=d_p[0]*w1;
-                        EM_S[INDEX2(2,0,4)]+=d_p[0]*w1;
-                        EM_S[INDEX2(0,2,4)]+=d_p[0]*w1;
-                        EM_S[INDEX2(2,2,4)]+=d_p[0]*w1;
-                    }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(k1);
-                        EM_F[0]+=2*w1*y_p[0];
-                        EM_F[2]+=2*w1*y_p[0];
-                    }
-                    const index_t firstNode=m_NN[0]*k1;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[1] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    const index_t e = domain->m_faceOffset[1]+k1;
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        EM_S[INDEX2(1,1,4)]+=d_p[0]*w1;
-                        EM_S[INDEX2(3,1,4)]+=d_p[0]*w1;
-                        EM_S[INDEX2(1,3,4)]+=d_p[0]*w1;
-                        EM_S[INDEX2(3,3,4)]+=d_p[0]*w1;
-                    }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        EM_F[1]+=2*w1*y_p[0];
-                        EM_F[3]+=2*w1*y_p[0];
-                    }
-                    const index_t firstNode=m_NN[0]*(k1+1)-2;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[2] > -1) {
-            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
-#pragma omp for
-                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    const index_t e = domain->m_faceOffset[2]+k0;
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        EM_S[INDEX2(0,0,4)]+=d_p[0]*w0;
-                        EM_S[INDEX2(1,0,4)]+=d_p[0]*w0;
-                        EM_S[INDEX2(0,1,4)]+=d_p[0]*w0;
-                        EM_S[INDEX2(1,1,4)]+=d_p[0]*w0;
-                    }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        EM_F[0]+=2*w0*y_p[0];
-                        EM_F[1]+=2*w0*y_p[0];
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double D_0 = D_p[INDEX2(k, m, numEq)];
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=16*D_0*w22;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=4*D_0*w22;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=16*D_0*w22;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=4*D_0*w22;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=4*D_0*w22;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=16*D_0*w22;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=4*D_0*w22;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=8*D_0*w22;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=16*D_0*w22;
+                                }
+                            }
+                        }
                     }
-                    const index_t firstNode=k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[3] > -1) {
-            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
-#pragma omp for
-                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    const index_t e = domain->m_faceOffset[3]+k0;
                     ///////////////
-                    // process d //
+                    // process X //
                     ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        EM_S[INDEX2(2,2,4)]+=d_p[0]*w0;
-                        EM_S[INDEX2(3,2,4)]+=d_p[0]*w0;
-                        EM_S[INDEX2(2,3,4)]+=d_p[0]*w0;
-                        EM_S[INDEX2(3,3,4)]+=d_p[0]*w0;
+                    if (!X.isEmpty()) {
+                        const double* X_p=X.getSampleDataRO(e);
+                        if (X.actsExpanded()) {
+                            for (index_t k=0; k<numEq; k++) {
+                                const double X_0_0 = X_p[INDEX3(k,0,0,numEq,2)];
+                                const double X_1_0 = X_p[INDEX3(k,1,0,numEq,2)];
+                                const double X_0_1 = X_p[INDEX3(k,0,1,numEq,2)];
+                                const double X_1_1 = X_p[INDEX3(k,1,1,numEq,2)];
+                                const double X_0_2 = X_p[INDEX3(k,0,2,numEq,2)];
+                                const double X_1_2 = X_p[INDEX3(k,1,2,numEq,2)];
+                                const double X_0_3 = X_p[INDEX3(k,0,3,numEq,2)];
+                                const double X_1_3 = X_p[INDEX3(k,1,3,numEq,2)];
+                                const double tmp0 = 6*w15*(X_0_2 + X_0_3);
+                                const double tmp1 = 6*w10*(X_0_0 + X_0_1);
+                                const double tmp2 = 6*w11*(X_1_0 + X_1_2);
+                                const double tmp3 = 6*w14*(X_1_1 + X_1_3);
+                                const double tmp4 = 6*w11*(X_1_1 + X_1_3);
+                                const double tmp5 = w25*(X_0_0 + X_0_1);
+                                const double tmp6 = w26*(X_0_2 + X_0_3);
+                                const double tmp7 = 6*w14*(X_1_0 + X_1_2);
+                                const double tmp8 = w27*(X_1_0 + X_1_2);
+                                const double tmp9 = w28*(X_1_1 + X_1_3);
+                                const double tmp10 = w25*(-X_0_2 - X_0_3);
+                                const double tmp11 = w26*(-X_0_0 - X_0_1);
+                                const double tmp12 = w27*(X_1_1 + X_1_3);
+                                const double tmp13 = w28*(X_1_0 + X_1_2);
+                                const double tmp14 = w25*(X_0_2 + X_0_3);
+                                const double tmp15 = w26*(X_0_0 + X_0_1);
+                                EM_F[INDEX2(k,0,numEq)]+=tmp0 + tmp1 + tmp2 + tmp3;
+                                EM_F[INDEX2(k,1,numEq)]+=tmp4 + tmp5 + tmp6 + tmp7;
+                                EM_F[INDEX2(k,2,numEq)]+=tmp10 + tmp11 + tmp8 + tmp9;
+                                EM_F[INDEX2(k,3,numEq)]+=tmp12 + tmp13 + tmp14 + tmp15;
+                            }
+                        } else { // constant data
+                            for (index_t k=0; k<numEq; k++) {
+                                const double wX0 = X_p[INDEX2(k, 0, numEq)]*w18;
+                                const double wX1 = X_p[INDEX2(k, 1, numEq)]*w19;
+                                EM_F[INDEX2(k,0,numEq)]+= 6*wX0 + 6*wX1;
+                                EM_F[INDEX2(k,1,numEq)]+=-6*wX0 + 6*wX1;
+                                EM_F[INDEX2(k,2,numEq)]+= 6*wX0 - 6*wX1;
+                                EM_F[INDEX2(k,3,numEq)]+=-6*wX0 - 6*wX1;
+                            }
+                        }
                     }
                     ///////////////
-                    // process y //
+                    // process Y //
                     ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        EM_F[2]+=2*w0*y_p[0];
-                        EM_F[3]+=2*w0*y_p[0];
+                    if (!Y.isEmpty()) {
+                        const double* Y_p=Y.getSampleDataRO(e);
+                        if (Y.actsExpanded()) {
+                            for (index_t k=0; k<numEq; k++) {
+                                const double Y_0 = Y_p[INDEX2(k, 0, numEq)];
+                                const double Y_1 = Y_p[INDEX2(k, 1, numEq)];
+                                const double Y_2 = Y_p[INDEX2(k, 2, numEq)];
+                                const double Y_3 = Y_p[INDEX2(k, 3, numEq)];
+                                const double tmp0 = 6*w22*(Y_1 + Y_2);
+                                const double tmp1 = 6*w22*(Y_0 + Y_3);
+                                EM_F[INDEX2(k,0,numEq)]+=6*Y_0*w20 + 6*Y_3*w21 + tmp0;
+                                EM_F[INDEX2(k,1,numEq)]+=6*Y_1*w20 + 6*Y_2*w21 + tmp1;
+                                EM_F[INDEX2(k,2,numEq)]+=6*Y_1*w21 + 6*Y_2*w20 + tmp1;
+                                EM_F[INDEX2(k,3,numEq)]+=6*Y_0*w21 + 6*Y_3*w20 + tmp0;
+                            }
+                        } else { // constant data
+                            for (index_t k=0; k<numEq; k++) {
+                                EM_F[INDEX2(k,0,numEq)]+=36*Y_p[k]*w22;
+                                EM_F[INDEX2(k,1,numEq)]+=36*Y_p[k]*w22;
+                                EM_F[INDEX2(k,2,numEq)]+=36*Y_p[k]*w22;
+                                EM_F[INDEX2(k,3,numEq)]+=36*Y_p[k]*w22;
+                            }
+                        }
                     }
-                    const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                }
-            } // end colouring
-        }
-    } // end of parallel section
+
+                    // add to matrix (if addEM_S) and RHS (if addEM_F)
+                    const index_t firstNode=m_NN[0]*k1+k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                            addEM_F, firstNode, numEq, numComp);
+                } // end k0 loop
+            } // end k1 loop
+        } // end of colouring
+    } // end of parallel region
 }
 
+/****************************************************************************/
+// PDE SYSTEM BOUNDARY
+/****************************************************************************/
+
 void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                Data& rhs, const Data& d, const Data& y) const
 {
@@ -1172,20 +1673,26 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
     const double w1 = w2*(-SQRT3 + 2);
     const double w3 = w2*(SQRT3 + 3);
     const double w4 = w2*(-SQRT3 + 3);
-    const bool addEM_S=!d.isEmpty();
-    const bool addEM_F=!y.isEmpty();
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
+    const bool addEM_S = !d.isEmpty();
+    const bool addEM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4*numEq*numComp, 0);
+        vector<double> EM_F(4*numEq, 0);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = k1;
                     ///////////////
                     // process d //
@@ -1198,20 +1705,20 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w2*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=d_0*w0 + d_1*w1;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=d_0*w1 + d_1*w0;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = d_0*w0 + d_1*w1;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = d_0*w1 + d_1*w0;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=4*d_0*w2;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=4*d_0*w2;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = 4*d_0*w2;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = 4*d_0*w2;
                                 }
                             }
                         }
@@ -1225,29 +1732,32 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,0,numEq)]+=w3*y_0 + w4*y_1;
-                                EM_F[INDEX2(k,2,numEq)]+=w3*y_1 + w4*y_0;
+                                EM_F[INDEX2(k,0,numEq)] = w3*y_0 + w4*y_1;
+                                EM_F[INDEX2(k,2,numEq)] = w3*y_1 + w4*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=6*w2*y_p[k];
-                                EM_F[INDEX2(k,2,numEq)]+=6*w2*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 6*w2*y_p[k];
+                                EM_F[INDEX2(k,2,numEq)] = 6*w2*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=m_NN[0]*k1;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                            addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
 
         if (domain->m_faceOffset[1] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
 #pragma omp for
                 for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = domain->m_faceOffset[1]+k1;
                     ///////////////
                     // process d //
@@ -1260,20 +1770,20 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w2*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=d_0*w0 + d_1*w1;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=d_0*w1 + d_1*w0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = d_0*w0 + d_1*w1;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = d_0*w1 + d_1*w0;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=4*d_0*w2;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=4*d_0*w2;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = 4*d_0*w2;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = 4*d_0*w2;
                                 }
                             }
                         }
@@ -1287,29 +1797,32 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,1,numEq)]+=w3*y_0 + w4*y_1;
-                                EM_F[INDEX2(k,3,numEq)]+=w3*y_1 + w4*y_0;
+                                EM_F[INDEX2(k,1,numEq)] = w3*y_0 + w4*y_1;
+                                EM_F[INDEX2(k,3,numEq)] = w3*y_1 + w4*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,1,numEq)]+=6*w2*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=6*w2*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 6*w2*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 6*w2*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=m_NN[0]*(k1+1)-2;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                            addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
 
         if (domain->m_faceOffset[2] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
 #pragma omp for
                 for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = domain->m_faceOffset[2]+k0;
                     ///////////////
                     // process d //
@@ -1322,20 +1835,20 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w5*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=d_0*w6 + d_1*w7;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=d_0*w7 + d_1*w6;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = d_0*w6 + d_1*w7;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = d_0*w7 + d_1*w6;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=4*d_0*w5;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=4*d_0*w5;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = 4*d_0*w5;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = 4*d_0*w5;
                                 }
                             }
                         }
@@ -1349,29 +1862,32 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,0,numEq)]+=w8*y_0 + w9*y_1;
-                                EM_F[INDEX2(k,1,numEq)]+=w8*y_1 + w9*y_0;
+                                EM_F[INDEX2(k,0,numEq)] = w8*y_0 + w9*y_1;
+                                EM_F[INDEX2(k,1,numEq)] = w8*y_1 + w9*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=6*w5*y_p[k];
-                                EM_F[INDEX2(k,1,numEq)]+=6*w5*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 6*w5*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 6*w5*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
 
         if (domain->m_faceOffset[3] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
 #pragma omp for
                 for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = domain->m_faceOffset[3]+k0;
                     ///////////////
                     // process d //
@@ -1384,20 +1900,20 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w5*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=d_0*w6 + d_1*w7;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=d_0*w7 + d_1*w6;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = d_0*w6 + d_1*w7;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = d_0*w7 + d_1*w6;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=4*d_0*w5;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=4*d_0*w5;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = 4*d_0*w5;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = 4*d_0*w5;
                                 }
                             }
                         }
@@ -1411,812 +1927,413 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,2,numEq)]+=w8*y_0 + w9*y_1;
-                                EM_F[INDEX2(k,3,numEq)]+=w8*y_1 + w9*y_0;
+                                EM_F[INDEX2(k,2,numEq)] = w8*y_0 + w9*y_1;
+                                EM_F[INDEX2(k,3,numEq)] = w8*y_1 + w9*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,2,numEq)]+=6*w5*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=6*w5*y_p[k];
-                            }
-                        }
-                    }
-                    const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
-                }
-            } // end colouring
-        }
-    } // end of parallel section
-}
-
-//protected
-void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
-                                         AbstractSystemMatrix* mat, Data& rhs,
-                                         const Data& d, const Data& y) const
-{
-    dim_t numEq, numComp;
-    if (!mat)
-        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
-    else {
-        numEq=mat->getRowBlockSize();
-        numComp=mat->getColumnBlockSize();
-    }
-    const double w0 = m_dx[0]/4;
-    const double w1 = m_dx[1]/4;
-    const bool addEM_S=!d.isEmpty();
-    const bool addEM_F=!y.isEmpty();
-    const int NE0 = m_NE[0];
-    const int NE1 = m_NE[1];
-    rhs.requireWrite();
-
-#pragma omp parallel
-    {
-        if (domain->m_faceOffset[0] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(k1);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w1;
-                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=tmp0;
-                            }
-                        }
-                    }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(k1);
-                        for (index_t k=0; k<numEq; k++) {
-                            EM_F[INDEX2(k,0,numEq)]+=2*w1*y_p[k];
-                            EM_F[INDEX2(k,2,numEq)]+=2*w1*y_p[k];
-                        }
-                    }
-                    const index_t firstNode=m_NN[0]*k1;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[1] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
-                    const index_t e = domain->m_faceOffset[1]+k1;
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w1;
-                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=tmp0;
-                            }
-                        }
-                    }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            EM_F[INDEX2(k,1,numEq)]+=2*w1*y_p[k];
-                            EM_F[INDEX2(k,3,numEq)]+=2*w1*y_p[k];
-                        }
-                    }
-                    const index_t firstNode=m_NN[0]*(k1+1)-2;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[2] > -1) {
-            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
-#pragma omp for
-                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
-                    const index_t e = domain->m_faceOffset[2]+k0;
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w0;
-                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=tmp0;
-                            }
-                        }
-                    }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            EM_F[INDEX2(k,0,numEq)]+=2*w0*y_p[k];
-                            EM_F[INDEX2(k,1,numEq)]+=2*w0*y_p[k];
-                        }
-                    }
-                    const index_t firstNode=k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
-                }
-            } // end colouring
-        }
-
-        if (domain->m_faceOffset[3] > -1) {
-            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
-#pragma omp for
-                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
-                    const index_t e = domain->m_faceOffset[3]+k0;
-                    ///////////////
-                    // process d //
-                    ///////////////
-                    if (addEM_S) {
-                        const double* d_p=d.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            for (index_t m=0; m<numComp; m++) {
-                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w0;
-                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp0;
-                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=tmp0;
+                                EM_F[INDEX2(k,2,numEq)] = 6*w5*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 6*w5*y_p[k];
                             }
                         }
                     }
-                    ///////////////
-                    // process y //
-                    ///////////////
-                    if (addEM_F) {
-                        const double* y_p=y.getSampleDataRO(e);
-                        for (index_t k=0; k<numEq; k++) {
-                            EM_F[INDEX2(k,2,numEq)]+=2*w0*y_p[k];
-                            EM_F[INDEX2(k,3,numEq)]+=2*w0*y_p[k];
-                        }
-                    }
                     const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                           addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
     } // end of parallel section
 }
 
-//protected
-void DefaultAssembler2D::assemblePDESingle(AbstractSystemMatrix* mat,
-                                      Data& rhs, const Data& A, const Data& B,
-                                      const Data& C, const Data& D,
-                                      const Data& X, const Data& Y) const
+/****************************************************************************/
+// PDE SYSTEM REDUCED
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+                                    Data& rhs, const Data& A, const Data& B,
+                                    const Data& C, const Data& D,
+                                    const Data& X, const Data& Y) const
 {
-    const double SQRT3 = 1.73205080756887719318;
-    const double w1 = 1.0/24.0;
-    const double w5 = -SQRT3/24 + 1.0/12;
-    const double w2 = -SQRT3/24 - 1.0/12;
-    const double w19 = -m_dx[0]/12;
-    const double w11 = w19*(SQRT3 + 3)/12;
-    const double w14 = w19*(-SQRT3 + 3)/12;
-    const double w16 = w19*(5*SQRT3 + 9)/12;
-    const double w17 = w19*(-5*SQRT3 + 9)/12;
-    const double w27 = w19*(-SQRT3 - 3)/2;
-    const double w28 = w19*(SQRT3 - 3)/2;
-    const double w18 = -m_dx[1]/12;
-    const double w12 = w18*(5*SQRT3 + 9)/12;
-    const double w13 = w18*(-5*SQRT3 + 9)/12;
-    const double w10 = w18*(SQRT3 + 3)/12;
-    const double w15 = w18*(-SQRT3 + 3)/12;
-    const double w25 = w18*(-SQRT3 - 3)/2;
-    const double w26 = w18*(SQRT3 - 3)/2;
-    const double w22 = m_dx[0]*m_dx[1]/144;
-    const double w20 = w22*(SQRT3 + 2);
-    const double w21 = w22*(-SQRT3 + 2);
-    const double w23 = w22*(4*SQRT3 + 7);
-    const double w24 = w22*(-4*SQRT3 + 7);
-    const double w3 = m_dx[0]/(24*m_dx[1]);
-    const double w7 = w3*(SQRT3 + 2);
-    const double w8 = w3*(-SQRT3 + 2);
-    const double w6 = -m_dx[1]/(24*m_dx[0]);
-    const double w0 = w6*(SQRT3 + 2);
-    const double w4 = w6*(-SQRT3 + 2);
+    dim_t numEq, numComp;
+    if (!mat)
+        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
+    else {
+        numEq=mat->getRowBlockSize();
+        numComp=mat->getColumnBlockSize();
+    }
+
+    const double w0 = 1./4;
+    const double w1 = m_dx[0]/8;
+    const double w2 = m_dx[1]/8;
+    const double w3 = m_dx[0]*m_dx[1]/16;
+    const double w4 = m_dx[0]/(4*m_dx[1]);
+    const double w5 = m_dx[1]/(4*m_dx[0]);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
+    const bool addEM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool addEM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4*numEq*numComp, 0);
+        vector<double> EM_F(4*numEq, 0);
+
         for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
             for (index_t k1=k1_0; k1<NE1; k1+=2) {
                 for (index_t k0=0; k0<NE0; ++k0)  {
-                    bool addEM_S=false;
-                    bool addEM_F=false;
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
+                    if (addEM_S)
+                        fill(EM_S.begin(), EM_S.end(), 0);
+                    if (addEM_F)
+                        fill(EM_F.begin(), EM_F.end(), 0);
                     const index_t e = k0 + NE0*k1;
                     ///////////////
                     // process A //
                     ///////////////
                     if (!A.isEmpty()) {
-                        addEM_S = true;
-                        const double* A_p = A.getSampleDataRO(e);
-                        if (A.actsExpanded()) {
-                            const double A_00_0 = A_p[INDEX3(0,0,0,2,2)];
-                            const double A_01_0 = A_p[INDEX3(0,1,0,2,2)];
-                            const double A_10_0 = A_p[INDEX3(1,0,0,2,2)];
-                            const double A_11_0 = A_p[INDEX3(1,1,0,2,2)];
-                            const double A_00_1 = A_p[INDEX3(0,0,1,2,2)];
-                            const double A_01_1 = A_p[INDEX3(0,1,1,2,2)];
-                            const double A_10_1 = A_p[INDEX3(1,0,1,2,2)];
-                            const double A_11_1 = A_p[INDEX3(1,1,1,2,2)];
-                            const double A_00_2 = A_p[INDEX3(0,0,2,2,2)];
-                            const double A_01_2 = A_p[INDEX3(0,1,2,2,2)];
-                            const double A_10_2 = A_p[INDEX3(1,0,2,2,2)];
-                            const double A_11_2 = A_p[INDEX3(1,1,2,2,2)];
-                            const double A_00_3 = A_p[INDEX3(0,0,3,2,2)];
-                            const double A_01_3 = A_p[INDEX3(0,1,3,2,2)];
-                            const double A_10_3 = A_p[INDEX3(1,0,3,2,2)];
-                            const double A_11_3 = A_p[INDEX3(1,1,3,2,2)];
-                            const double tmp0 = w3*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
-                            const double tmp1 = w1*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
-                            const double tmp2 = w4*(A_00_2 + A_00_3);
-                            const double tmp3 = w0*(A_00_0 + A_00_1);
-                            const double tmp4 = w5*(A_01_2 - A_10_3);
-                            const double tmp5 = w2*(-A_01_1 + A_10_0);
-                            const double tmp6 = w5*(A_01_3 + A_10_0);
-                            const double tmp7 = w3*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
-                            const double tmp8 = w6*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
-                            const double tmp9 = w1*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
-                            const double tmp10 = w2*(-A_01_0 - A_10_3);
-                            const double tmp11 = w4*(A_00_0 + A_00_1);
-                            const double tmp12 = w0*(A_00_2 + A_00_3);
-                            const double tmp13 = w5*(A_01_1 - A_10_0);
-                            const double tmp14 = w2*(-A_01_2 + A_10_3);
-                            const double tmp15 = w7*(A_11_0 + A_11_2);
-                            const double tmp16 = w4*(-A_00_2 - A_00_3);
-                            const double tmp17 = w0*(-A_00_0 - A_00_1);
-                            const double tmp18 = w5*(A_01_3 + A_10_3);
-                            const double tmp19 = w8*(A_11_1 + A_11_3);
-                            const double tmp20 = w2*(-A_01_0 - A_10_0);
-                            const double tmp21 = w7*(A_11_1 + A_11_3);
-                            const double tmp22 = w4*(-A_00_0 - A_00_1);
-                            const double tmp23 = w0*(-A_00_2 - A_00_3);
-                            const double tmp24 = w5*(A_01_0 + A_10_0);
-                            const double tmp25 = w8*(A_11_0 + A_11_2);
-                            const double tmp26 = w2*(-A_01_3 - A_10_3);
-                            const double tmp27 = w5*(-A_01_1 - A_10_2);
-                            const double tmp28 = w1*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
-                            const double tmp29 = w2*(A_01_2 + A_10_1);
-                            const double tmp30 = w7*(-A_11_1 - A_11_3);
-                            const double tmp31 = w1*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
-                            const double tmp32 = w5*(-A_01_0 + A_10_2);
-                            const double tmp33 = w8*(-A_11_0 - A_11_2);
-                            const double tmp34 = w6*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
-                            const double tmp35 = w2*(A_01_3 - A_10_1);
-                            const double tmp36 = w5*(A_01_0 + A_10_3);
-                            const double tmp37 = w2*(-A_01_3 - A_10_0);
-                            const double tmp38 = w7*(-A_11_0 - A_11_2);
-                            const double tmp39 = w5*(-A_01_3 + A_10_1);
-                            const double tmp40 = w8*(-A_11_1 - A_11_3);
-                            const double tmp41 = w2*(A_01_0 - A_10_2);
-                            const double tmp42 = w5*(A_01_1 - A_10_3);
-                            const double tmp43 = w2*(-A_01_2 + A_10_0);
-                            const double tmp44 = w5*(A_01_2 - A_10_0);
-                            const double tmp45 = w2*(-A_01_1 + A_10_3);
-                            const double tmp46 = w5*(-A_01_0 + A_10_1);
-                            const double tmp47 = w2*(A_01_3 - A_10_2);
-                            const double tmp48 = w5*(-A_01_1 - A_10_1);
-                            const double tmp49 = w2*(A_01_2 + A_10_2);
-                            const double tmp50 = w5*(-A_01_3 + A_10_2);
-                            const double tmp51 = w2*(A_01_0 - A_10_1);
-                            const double tmp52 = w5*(-A_01_2 - A_10_1);
-                            const double tmp53 = w2*(A_01_1 + A_10_2);
-                            const double tmp54 = w5*(-A_01_2 - A_10_2);
-                            const double tmp55 = w2*(A_01_1 + A_10_1);
-                            EM_S[INDEX2(0,0,4)]+=tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp20 + tmp9;
-                            EM_S[INDEX2(0,1,4)]+=tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5;
-                            EM_S[INDEX2(0,2,4)]+=tmp31 + tmp34 + tmp38 + tmp39 + tmp40 + tmp41;
-                            EM_S[INDEX2(0,3,4)]+=tmp28 + tmp52 + tmp53 + tmp7 + tmp8;
-                            EM_S[INDEX2(1,0,4)]+=tmp0 + tmp2 + tmp3 + tmp31 + tmp50 + tmp51;
-                            EM_S[INDEX2(1,1,4)]+=tmp16 + tmp17 + tmp21 + tmp25 + tmp28 + tmp54 + tmp55;
-                            EM_S[INDEX2(1,2,4)]+=tmp10 + tmp6 + tmp7 + tmp8 + tmp9;
-                            EM_S[INDEX2(1,3,4)]+=tmp1 + tmp30 + tmp33 + tmp34 + tmp44 + tmp45;
-                            EM_S[INDEX2(2,0,4)]+=tmp1 + tmp34 + tmp38 + tmp40 + tmp42 + tmp43;
-                            EM_S[INDEX2(2,1,4)]+=tmp36 + tmp37 + tmp7 + tmp8 + tmp9;
-                            EM_S[INDEX2(2,2,4)]+=tmp15 + tmp19 + tmp22 + tmp23 + tmp28 + tmp48 + tmp49;
-                            EM_S[INDEX2(2,3,4)]+=tmp0 + tmp11 + tmp12 + tmp31 + tmp46 + tmp47;
-                            EM_S[INDEX2(3,0,4)]+=tmp27 + tmp28 + tmp29 + tmp7 + tmp8;
-                            EM_S[INDEX2(3,1,4)]+=tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
-                            EM_S[INDEX2(3,2,4)]+=tmp0 + tmp1 + tmp11 + tmp12 + tmp13 + tmp14;
-                            EM_S[INDEX2(3,3,4)]+=tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp9;
-                        } else { // constant data
-                            const double A_00 = A_p[INDEX2(0,0,2)];
-                            const double A_01 = A_p[INDEX2(0,1,2)];
-                            const double A_10 = A_p[INDEX2(1,0,2)];
-                            const double A_11 = A_p[INDEX2(1,1,2)];
-                            const double tmp0 = 6*w1*(A_01 - A_10);
-                            const double tmp1 = 6*w1*(A_01 + A_10);
-                            const double tmp2 = 6*w1*(-A_01 - A_10);
-                            const double tmp3 = 6*w1*(-A_01 + A_10);
-                            EM_S[INDEX2(0,0,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
-                            EM_S[INDEX2(0,1,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
-                            EM_S[INDEX2(0,2,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
-                            EM_S[INDEX2(0,3,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
-                            EM_S[INDEX2(1,0,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
-                            EM_S[INDEX2(1,1,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
-                            EM_S[INDEX2(1,2,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
-                            EM_S[INDEX2(1,3,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
-                            EM_S[INDEX2(2,0,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp0;
-                            EM_S[INDEX2(2,1,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp1;
-                            EM_S[INDEX2(2,2,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp2;
-                            EM_S[INDEX2(2,3,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp3;
-                            EM_S[INDEX2(3,0,4)]+=4*A_00*w6 - 4*A_11*w3 + tmp2;
-                            EM_S[INDEX2(3,1,4)]+=-4*A_00*w6 - 8*A_11*w3 + tmp3;
-                            EM_S[INDEX2(3,2,4)]+=8*A_00*w6 + 4*A_11*w3 + tmp0;
-                            EM_S[INDEX2(3,3,4)]+=-8*A_00*w6 + 8*A_11*w3 + tmp1;
-                        }
-                    }
-                    ///////////////
-                    // process B //
-                    ///////////////
-                    if (!B.isEmpty()) {
-                        addEM_S=true;
-                        const double* B_p=B.getSampleDataRO(e);
-                        if (B.actsExpanded()) {
-                            const double B_0_0 = B_p[INDEX2(0,0,2)];
-                            const double B_1_0 = B_p[INDEX2(1,0,2)];
-                            const double B_0_1 = B_p[INDEX2(0,1,2)];
-                            const double B_1_1 = B_p[INDEX2(1,1,2)];
-                            const double B_0_2 = B_p[INDEX2(0,2,2)];
-                            const double B_1_2 = B_p[INDEX2(1,2,2)];
-                            const double B_0_3 = B_p[INDEX2(0,3,2)];
-                            const double B_1_3 = B_p[INDEX2(1,3,2)];
-                            const double tmp0 = w11*(B_1_0 + B_1_1);
-                            const double tmp1 = w14*(B_1_2 + B_1_3);
-                            const double tmp2 = w15*(-B_0_1 - B_0_3);
-                            const double tmp3 = w10*(-B_0_0 - B_0_2);
-                            const double tmp4 = w11*(B_1_2 + B_1_3);
-                            const double tmp5 = w14*(B_1_0 + B_1_1);
-                            const double tmp6 = w11*(-B_1_2 - B_1_3);
-                            const double tmp7 = w14*(-B_1_0 - B_1_1);
-                            const double tmp8 = w11*(-B_1_0 - B_1_1);
-                            const double tmp9 = w14*(-B_1_2 - B_1_3);
-                            const double tmp10 = w10*(-B_0_1 - B_0_3);
-                            const double tmp11 = w15*(-B_0_0 - B_0_2);
-                            const double tmp12 = w15*(B_0_0 + B_0_2);
-                            const double tmp13 = w10*(B_0_1 + B_0_3);
-                            const double tmp14 = w10*(B_0_0 + B_0_2);
-                            const double tmp15 = w15*(B_0_1 + B_0_3);
-                            EM_S[INDEX2(0,0,4)]+=B_0_0*w12 + B_0_1*w10 + B_0_2*w15 + B_0_3*w13 + B_1_0*w16 + B_1_1*w14 + B_1_2*w11 + B_1_3*w17;
-                            EM_S[INDEX2(0,1,4)]+=B_0_0*w10 + B_0_1*w12 + B_0_2*w13 + B_0_3*w15 + tmp0 + tmp1;
-                            EM_S[INDEX2(0,2,4)]+=B_1_0*w11 + B_1_1*w17 + B_1_2*w16 + B_1_3*w14 + tmp14 + tmp15;
-                            EM_S[INDEX2(0,3,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
-                            EM_S[INDEX2(1,0,4)]+=-B_0_0*w12 - B_0_1*w10 - B_0_2*w15 - B_0_3*w13 + tmp0 + tmp1;
-                            EM_S[INDEX2(1,1,4)]+=-B_0_0*w10 - B_0_1*w12 - B_0_2*w13 - B_0_3*w15 + B_1_0*w14 + B_1_1*w16 + B_1_2*w17 + B_1_3*w11;
-                            EM_S[INDEX2(1,2,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
-                            EM_S[INDEX2(1,3,4)]+=B_1_0*w17 + B_1_1*w11 + B_1_2*w14 + B_1_3*w16 + tmp10 + tmp11;
-                            EM_S[INDEX2(2,0,4)]+=-B_1_0*w16 - B_1_1*w14 - B_1_2*w11 - B_1_3*w17 + tmp14 + tmp15;
-                            EM_S[INDEX2(2,1,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
-                            EM_S[INDEX2(2,2,4)]+=B_0_0*w15 + B_0_1*w13 + B_0_2*w12 + B_0_3*w10 - B_1_0*w11 - B_1_1*w17 - B_1_2*w16 - B_1_3*w14;
-                            EM_S[INDEX2(2,3,4)]+=B_0_0*w13 + B_0_1*w15 + B_0_2*w10 + B_0_3*w12 + tmp6 + tmp7;
-                            EM_S[INDEX2(3,0,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
-                            EM_S[INDEX2(3,1,4)]+=-B_1_0*w14 - B_1_1*w16 - B_1_2*w17 - B_1_3*w11 + tmp10 + tmp11;
-                            EM_S[INDEX2(3,2,4)]+=-B_0_0*w15 - B_0_1*w13 - B_0_2*w12 - B_0_3*w10 + tmp6 + tmp7;
-                            EM_S[INDEX2(3,3,4)]+=-B_0_0*w13 - B_0_1*w15 - B_0_2*w10 - B_0_3*w12 - B_1_0*w17 - B_1_1*w11 - B_1_2*w14 - B_1_3*w16;
-                        } else { // constant data
-                            const double B_0 = B_p[0];
-                            const double B_1 = B_p[1];
-                            EM_S[INDEX2(0,0,4)]+= 2*B_0*w18 + 2*B_1*w19;
-                            EM_S[INDEX2(0,1,4)]+= 2*B_0*w18 +   B_1*w19;
-                            EM_S[INDEX2(0,2,4)]+=   B_0*w18 + 2*B_1*w19;
-                            EM_S[INDEX2(0,3,4)]+=   B_0*w18 +   B_1*w19;
-                            EM_S[INDEX2(1,0,4)]+=-2*B_0*w18 +   B_1*w19;
-                            EM_S[INDEX2(1,1,4)]+=-2*B_0*w18 + 2*B_1*w19;
-                            EM_S[INDEX2(1,2,4)]+=  -B_0*w18 +   B_1*w19;
-                            EM_S[INDEX2(1,3,4)]+=  -B_0*w18 + 2*B_1*w19;
-                            EM_S[INDEX2(2,0,4)]+=   B_0*w18 - 2*B_1*w19;
-                            EM_S[INDEX2(2,1,4)]+=   B_0*w18 -   B_1*w19;
-                            EM_S[INDEX2(2,2,4)]+= 2*B_0*w18 - 2*B_1*w19;
-                            EM_S[INDEX2(2,3,4)]+= 2*B_0*w18 -   B_1*w19;
-                            EM_S[INDEX2(3,0,4)]+=  -B_0*w18 -   B_1*w19;
-                            EM_S[INDEX2(3,1,4)]+=  -B_0*w18 - 2*B_1*w19;
-                            EM_S[INDEX2(3,2,4)]+=-2*B_0*w18 -   B_1*w19;
-                            EM_S[INDEX2(3,3,4)]+=-2*B_0*w18 - 2*B_1*w19;
+                        const double* A_p=A.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double Aw00 = A_p[INDEX4(k,0,m,0, numEq,2, numComp)]*w5;
+                                const double Aw01 = A_p[INDEX4(k,0,m,1, numEq,2, numComp)]*w0;
+                                const double Aw10 = A_p[INDEX4(k,1,m,0, numEq,2, numComp)]*w0;
+                                const double Aw11 = A_p[INDEX4(k,1,m,1, numEq,2, numComp)]*w4;
+                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+= Aw00 + Aw01 + Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-Aw00 - Aw01 + Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+= Aw00 + Aw01 - Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=-Aw00 - Aw01 - Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-Aw00 + Aw01 - Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+= Aw00 - Aw01 - Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=-Aw00 + Aw01 + Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+= Aw00 - Aw01 + Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+= Aw00 - Aw01 + Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=-Aw00 + Aw01 + Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+= Aw00 - Aw01 - Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-Aw00 + Aw01 - Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=-Aw00 - Aw01 - Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+= Aw00 + Aw01 - Aw10 - Aw11;
+                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-Aw00 - Aw01 + Aw10 + Aw11;
+                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+= Aw00 + Aw01 + Aw10 + Aw11;
+                            }
+                        }
+                    }
+                    ///////////////
+                    // process B //
+                    ///////////////
+                    if (!B.isEmpty()) {
+                        const double* B_p=B.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double wB0 = B_p[INDEX3(k,0,m, numEq, 2)]*w2;
+                                const double wB1 = B_p[INDEX3(k,1,m, numEq, 2)]*w1;
+                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=-wB0 - wB1;
+                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=-wB0 - wB1;
+                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-wB0 - wB1;
+                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=-wB0 - wB1;
+                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+= wB0 - wB1;
+                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+= wB0 - wB1;
+                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+= wB0 - wB1;
+                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+= wB0 - wB1;
+                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-wB0 + wB1;
+                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=-wB0 + wB1;
+                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=-wB0 + wB1;
+                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=-wB0 + wB1;
+                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+= wB0 + wB1;
+                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+= wB0 + wB1;
+                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+= wB0 + wB1;
+                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+= wB0 + wB1;
+                            }
                         }
                     }
                     ///////////////
                     // process C //
                     ///////////////
                     if (!C.isEmpty()) {
-                        addEM_S=true;
                         const double* C_p=C.getSampleDataRO(e);
-                        if (C.actsExpanded()) {
-                            const double C_0_0 = C_p[INDEX2(0,0,2)];
-                            const double C_1_0 = C_p[INDEX2(1,0,2)];
-                            const double C_0_1 = C_p[INDEX2(0,1,2)];
-                            const double C_1_1 = C_p[INDEX2(1,1,2)];
-                            const double C_0_2 = C_p[INDEX2(0,2,2)];
-                            const double C_1_2 = C_p[INDEX2(1,2,2)];
-                            const double C_0_3 = C_p[INDEX2(0,3,2)];
-                            const double C_1_3 = C_p[INDEX2(1,3,2)];
-                            const double tmp0 = w11*(C_1_0 + C_1_1);
-                            const double tmp1 = w14*(C_1_2 + C_1_3);
-                            const double tmp2 = w15*(C_0_0 + C_0_2);
-                            const double tmp3 = w10*(C_0_1 + C_0_3);
-                            const double tmp4 = w11*(-C_1_0 - C_1_1);
-                            const double tmp5 = w14*(-C_1_2 - C_1_3);
-                            const double tmp6 = w11*(-C_1_2 - C_1_3);
-                            const double tmp7 = w14*(-C_1_0 - C_1_1);
-                            const double tmp8 = w11*(C_1_2 + C_1_3);
-                            const double tmp9 = w14*(C_1_0 + C_1_1);
-                            const double tmp10 = w10*(-C_0_1 - C_0_3);
-                            const double tmp11 = w15*(-C_0_0 - C_0_2);
-                            const double tmp12 = w15*(-C_0_1 - C_0_3);
-                            const double tmp13 = w10*(-C_0_0 - C_0_2);
-                            const double tmp14 = w10*(C_0_0 + C_0_2);
-                            const double tmp15 = w15*(C_0_1 + C_0_3);
-                            EM_S[INDEX2(0,0,4)]+=C_0_0*w12 + C_0_1*w10 + C_0_2*w15 + C_0_3*w13 + C_1_0*w16 + C_1_1*w14 + C_1_2*w11 + C_1_3*w17;
-                            EM_S[INDEX2(0,1,4)]+=-C_0_0*w12 - C_0_1*w10 - C_0_2*w15 - C_0_3*w13 + tmp0 + tmp1;
-                            EM_S[INDEX2(0,2,4)]+=-C_1_0*w16 - C_1_1*w14 - C_1_2*w11 - C_1_3*w17 + tmp14 + tmp15;
-                            EM_S[INDEX2(0,3,4)]+=tmp12 + tmp13 + tmp4 + tmp5;
-                            EM_S[INDEX2(1,0,4)]+=C_0_0*w10 + C_0_1*w12 + C_0_2*w13 + C_0_3*w15 + tmp0 + tmp1;
-                            EM_S[INDEX2(1,1,4)]+=-C_0_0*w10 - C_0_1*w12 - C_0_2*w13 - C_0_3*w15 + C_1_0*w14 + C_1_1*w16 + C_1_2*w17 + C_1_3*w11;
-                            EM_S[INDEX2(1,2,4)]+=tmp2 + tmp3 + tmp4 + tmp5;
-                            EM_S[INDEX2(1,3,4)]+=-C_1_0*w14 - C_1_1*w16 - C_1_2*w17 - C_1_3*w11 + tmp10 + tmp11;
-                            EM_S[INDEX2(2,0,4)]+=C_1_0*w11 + C_1_1*w17 + C_1_2*w16 + C_1_3*w14 + tmp14 + tmp15;
-                            EM_S[INDEX2(2,1,4)]+=tmp12 + tmp13 + tmp8 + tmp9;
-                            EM_S[INDEX2(2,2,4)]+=C_0_0*w15 + C_0_1*w13 + C_0_2*w12 + C_0_3*w10 - C_1_0*w11 - C_1_1*w17 - C_1_2*w16 - C_1_3*w14;
-                            EM_S[INDEX2(2,3,4)]+=-C_0_0*w15 - C_0_1*w13 - C_0_2*w12 - C_0_3*w10 + tmp6 + tmp7;
-                            EM_S[INDEX2(3,0,4)]+=tmp2 + tmp3 + tmp8 + tmp9;
-                            EM_S[INDEX2(3,1,4)]+=C_1_0*w17 + C_1_1*w11 + C_1_2*w14 + C_1_3*w16 + tmp10 + tmp11;
-                            EM_S[INDEX2(3,2,4)]+=C_0_0*w13 + C_0_1*w15 + C_0_2*w10 + C_0_3*w12 + tmp6 + tmp7;
-                            EM_S[INDEX2(3,3,4)]+=-C_0_0*w13 - C_0_1*w15 - C_0_2*w10 - C_0_3*w12 - C_1_0*w17 - C_1_1*w11 - C_1_2*w14 - C_1_3*w16;
-                        } else { // constant data
-                            const double C_0 = C_p[0];
-                            const double C_1 = C_p[1];
-                            EM_S[INDEX2(0,0,4)]+= 2*C_0*w18 + 2*C_1*w19;
-                            EM_S[INDEX2(0,1,4)]+=-2*C_0*w18 +   C_1*w19;
-                            EM_S[INDEX2(0,2,4)]+=   C_0*w18 - 2*C_1*w19;
-                            EM_S[INDEX2(0,3,4)]+=  -C_0*w18 -   C_1*w19;
-                            EM_S[INDEX2(1,0,4)]+= 2*C_0*w18 +   C_1*w19;
-                            EM_S[INDEX2(1,1,4)]+=-2*C_0*w18 + 2*C_1*w19;
-                            EM_S[INDEX2(1,2,4)]+=   C_0*w18 -   C_1*w19;
-                            EM_S[INDEX2(1,3,4)]+=  -C_0*w18 - 2*C_1*w19;
-                            EM_S[INDEX2(2,0,4)]+=   C_0*w18 + 2*C_1*w19;
-                            EM_S[INDEX2(2,1,4)]+=  -C_0*w18 +   C_1*w19;
-                            EM_S[INDEX2(2,2,4)]+= 2*C_0*w18 - 2*C_1*w19;
-                            EM_S[INDEX2(2,3,4)]+=-2*C_0*w18 -   C_1*w19;
-                            EM_S[INDEX2(3,0,4)]+=   C_0*w18 +   C_1*w19;
-                            EM_S[INDEX2(3,1,4)]+=  -C_0*w18 + 2*C_1*w19;
-                            EM_S[INDEX2(3,2,4)]+= 2*C_0*w18 -   C_1*w19;
-                            EM_S[INDEX2(3,3,4)]+=-2*C_0*w18 - 2*C_1*w19;
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double wC0 = C_p[INDEX3(k, m, 0, numEq, numComp)]*w2;
+                                const double wC1 = C_p[INDEX3(k, m, 1, numEq, numComp)]*w1;
+                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=-wC0 - wC1;
+                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=-wC0 - wC1;
+                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=-wC0 - wC1;
+                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=-wC0 - wC1;
+                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+= wC0 - wC1;
+                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+= wC0 - wC1;
+                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+= wC0 - wC1;
+                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+= wC0 - wC1;
+                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=-wC0 + wC1;
+                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=-wC0 + wC1;
+                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=-wC0 + wC1;
+                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=-wC0 + wC1;
+                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+= wC0 + wC1;
+                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+= wC0 + wC1;
+                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+= wC0 + wC1;
+                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+= wC0 + wC1;
+                            }
                         }
                     }
                     ///////////////
                     // process D //
                     ///////////////
                     if (!D.isEmpty()) {
-                        addEM_S=true;
                         const double* D_p=D.getSampleDataRO(e);
-                        if (D.actsExpanded()) {
-                            const double D_0 = D_p[0];
-                            const double D_1 = D_p[1];
-                            const double D_2 = D_p[2];
-                            const double D_3 = D_p[3];
-                            const double tmp0 = w21*(D_2 + D_3);
-                            const double tmp1 = w20*(D_0 + D_1);
-                            const double tmp2 = w22*(D_0 + D_1 + D_2 + D_3);
-                            const double tmp3 = w21*(D_0 + D_1);
-                            const double tmp4 = w20*(D_2 + D_3);
-                            const double tmp5 = w22*(D_1 + D_2);
-                            const double tmp6 = w21*(D_0 + D_2);
-                            const double tmp7 = w20*(D_1 + D_3);
-                            const double tmp8 = w21*(D_1 + D_3);
-                            const double tmp9 = w20*(D_0 + D_2);
-                            const double tmp10 = w22*(D_0 + D_3);
-                            EM_S[INDEX2(0,0,4)]+=D_0*w23 + D_3*w24 + tmp5;
-                            EM_S[INDEX2(0,1,4)]+=tmp0 + tmp1;
-                            EM_S[INDEX2(0,2,4)]+=tmp8 + tmp9;
-                            EM_S[INDEX2(0,3,4)]+=tmp2;
-                            EM_S[INDEX2(1,0,4)]+=tmp0 + tmp1;
-                            EM_S[INDEX2(1,1,4)]+=D_1*w23 + D_2*w24 + tmp10;
-                            EM_S[INDEX2(1,2,4)]+=tmp2;
-                            EM_S[INDEX2(1,3,4)]+=tmp6 + tmp7;
-                            EM_S[INDEX2(2,0,4)]+=tmp8 + tmp9;
-                            EM_S[INDEX2(2,1,4)]+=tmp2;
-                            EM_S[INDEX2(2,2,4)]+=D_1*w24 + D_2*w23 + tmp10;
-                            EM_S[INDEX2(2,3,4)]+=tmp3 + tmp4;
-                            EM_S[INDEX2(3,0,4)]+=tmp2;
-                            EM_S[INDEX2(3,1,4)]+=tmp6 + tmp7;
-                            EM_S[INDEX2(3,2,4)]+=tmp3 + tmp4;
-                            EM_S[INDEX2(3,3,4)]+=D_0*w24 + D_3*w23 + tmp5;
-                        } else { // constant data
-                            const double D_0 = D_p[0];
-                            EM_S[INDEX2(0,0,4)]+=16*D_0*w22;
-                            EM_S[INDEX2(0,1,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(0,2,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(0,3,4)]+=4*D_0*w22;
-                            EM_S[INDEX2(1,0,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(1,1,4)]+=16*D_0*w22;
-                            EM_S[INDEX2(1,2,4)]+=4*D_0*w22;
-                            EM_S[INDEX2(1,3,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(2,0,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(2,1,4)]+=4*D_0*w22;
-                            EM_S[INDEX2(2,2,4)]+=16*D_0*w22;
-                            EM_S[INDEX2(2,3,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(3,0,4)]+=4*D_0*w22;
-                            EM_S[INDEX2(3,1,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(3,2,4)]+=8*D_0*w22;
-                            EM_S[INDEX2(3,3,4)]+=16*D_0*w22;
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double wD0 = D_p[INDEX2(k, m, numEq)]*w3;
+                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,3,0,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,2,1,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,1,2,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,0,3,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=wD0;
+                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=wD0;
+                            }
                         }
                     }
                     ///////////////
                     // process X //
                     ///////////////
                     if (!X.isEmpty()) {
-                        addEM_F=true;
                         const double* X_p=X.getSampleDataRO(e);
-                        if (X.actsExpanded()) {
-                            const double X_0_0 = X_p[INDEX2(0,0,2)];
-                            const double X_1_0 = X_p[INDEX2(1,0,2)];
-                            const double X_0_1 = X_p[INDEX2(0,1,2)];
-                            const double X_1_1 = X_p[INDEX2(1,1,2)];
-                            const double X_0_2 = X_p[INDEX2(0,2,2)];
-                            const double X_1_2 = X_p[INDEX2(1,2,2)];
-                            const double X_0_3 = X_p[INDEX2(0,3,2)];
-                            const double X_1_3 = X_p[INDEX2(1,3,2)];
-                            const double tmp0 = 6*w15*(X_0_2 + X_0_3);
-                            const double tmp1 = 6*w10*(X_0_0 + X_0_1);
-                            const double tmp2 = 6*w11*(X_1_0 + X_1_2);
-                            const double tmp3 = 6*w14*(X_1_1 + X_1_3);
-                            const double tmp4 = 6*w11*(X_1_1 + X_1_3);
-                            const double tmp5 = w25*(X_0_0 + X_0_1);
-                            const double tmp6 = w26*(X_0_2 + X_0_3);
-                            const double tmp7 = 6*w14*(X_1_0 + X_1_2);
-                            const double tmp8 = w27*(X_1_0 + X_1_2);
-                            const double tmp9 = w28*(X_1_1 + X_1_3);
-                            const double tmp10 = w25*(-X_0_2 - X_0_3);
-                            const double tmp11 = w26*(-X_0_0 - X_0_1);
-                            const double tmp12 = w27*(X_1_1 + X_1_3);
-                            const double tmp13 = w28*(X_1_0 + X_1_2);
-                            const double tmp14 = w25*(X_0_2 + X_0_3);
-                            const double tmp15 = w26*(X_0_0 + X_0_1);
-                            EM_F[0]+=tmp0 + tmp1 + tmp2 + tmp3;
-                            EM_F[1]+=tmp4 + tmp5 + tmp6 + tmp7;
-                            EM_F[2]+=tmp10 + tmp11 + tmp8 + tmp9;
-                            EM_F[3]+=tmp12 + tmp13 + tmp14 + tmp15;
-                        } else { // constant data
-                            const double X_0 = X_p[0];
-                            const double X_1 = X_p[1];
-                            EM_F[0]+= 6*X_0*w18 + 6*X_1*w19;
-                            EM_F[1]+=-6*X_0*w18 + 6*X_1*w19;
-                            EM_F[2]+= 6*X_0*w18 - 6*X_1*w19;
-                            EM_F[3]+=-6*X_0*w18 - 6*X_1*w19;
-                        }
-                    }
-                    ///////////////
-                    // process Y //
-                    ///////////////
-                    if (!Y.isEmpty()) {
-                        addEM_F=true;
-                        const double* Y_p=Y.getSampleDataRO(e);
-                        if (Y.actsExpanded()) {
-                            const double Y_0 = Y_p[0];
-                            const double Y_1 = Y_p[1];
-                            const double Y_2 = Y_p[2];
-                            const double Y_3 = Y_p[3];
-                            const double tmp0 = 6*w22*(Y_1 + Y_2);
-                            const double tmp1 = 6*w22*(Y_0 + Y_3);
-                            EM_F[0]+=6*Y_0*w20 + 6*Y_3*w21 + tmp0;
-                            EM_F[1]+=6*Y_1*w20 + 6*Y_2*w21 + tmp1;
-                            EM_F[2]+=6*Y_1*w21 + 6*Y_2*w20 + tmp1;
-                            EM_F[3]+=6*Y_0*w21 + 6*Y_3*w20 + tmp0;
-                        } else { // constant data
-                            EM_F[0]+=36*Y_p[0]*w22;
-                            EM_F[1]+=36*Y_p[0]*w22;
-                            EM_F[2]+=36*Y_p[0]*w22;
-                            EM_F[3]+=36*Y_p[0]*w22;
+                        for (index_t k=0; k<numEq; k++) {
+                            const double wX0 = 4*X_p[INDEX2(k, 0, numEq)]*w2;
+                            const double wX1 = 4*X_p[INDEX2(k, 1, numEq)]*w1;
+                            EM_F[INDEX2(k,0,numEq)]+=-wX0 - wX1;
+                            EM_F[INDEX2(k,1,numEq)]+= wX0 - wX1;
+                            EM_F[INDEX2(k,2,numEq)]+=-wX0 + wX1;
+                            EM_F[INDEX2(k,3,numEq)]+= wX0 + wX1;
+                        }
+                    }
+                    ///////////////
+                    // process Y //
+                    ///////////////
+                    if (!Y.isEmpty()) {
+                        const double* Y_p=Y.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            EM_F[INDEX2(k,0,numEq)]+=4*Y_p[k]*w3;
+                            EM_F[INDEX2(k,1,numEq)]+=4*Y_p[k]*w3;
+                            EM_F[INDEX2(k,2,numEq)]+=4*Y_p[k]*w3;
+                            EM_F[INDEX2(k,3,numEq)]+=4*Y_p[k]*w3;
                         }
                     }
 
                     // add to matrix (if addEM_S) and RHS (if addEM_F)
                     const index_t firstNode=m_NN[0]*k1+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
                 } // end k0 loop
             } // end k1 loop
         } // end of colouring
     } // end of parallel region
 }
 
-//protected
-void DefaultAssembler2D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
-                                    Data& rhs, const Data& A, const Data& B,
-                                    const Data& C, const Data& D,
-                                    const Data& X, const Data& Y) const
+/****************************************************************************/
+// PDE SYSTEM REDUCED BOUNDARY
+/****************************************************************************/
+
+void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
+                                         AbstractSystemMatrix* mat, Data& rhs,
+                                         const Data& d, const Data& y) const
 {
-    const double w0 = 1./4;
-    const double w1 = m_dx[0]/8;
-    const double w2 = m_dx[1]/8;
-    const double w3 = m_dx[0]*m_dx[1]/16;
-    const double w4 = m_dx[0]/(4*m_dx[1]);
-    const double w5 = m_dx[1]/(4*m_dx[0]);
+    dim_t numEq, numComp;
+    if (!mat)
+        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
+    else {
+        numEq=mat->getRowBlockSize();
+        numComp=mat->getColumnBlockSize();
+    }
+    const double w0 = m_dx[0]/4;
+    const double w1 = m_dx[1]/4;
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
+    const bool addEM_S = !d.isEmpty();
+    const bool addEM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
-        for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
+        vector<double> EM_S(4*4*numEq*numComp, 0);
+        vector<double> EM_F(4*numEq, 0);
+
+        if (domain->m_faceOffset[0] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
-            for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                for (index_t k0=0; k0<NE0; ++k0)  {
-                    bool addEM_S=false;
-                    bool addEM_F=false;
-                    vector<double> EM_S(4*4, 0);
-                    vector<double> EM_F(4, 0);
-                    const index_t e = k0 + NE0*k1;
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
                     ///////////////
-                    // process A //
+                    // process d //
                     ///////////////
-                    if (!A.isEmpty()) {
-                        addEM_S=true;
-                        const double* A_p=A.getSampleDataRO(e);
-                        const double A_00 = A_p[INDEX2(0,0,2)];
-                        const double A_10 = A_p[INDEX2(1,0,2)];
-                        const double A_01 = A_p[INDEX2(0,1,2)];
-                        const double A_11 = A_p[INDEX2(1,1,2)];
-                        const double tmp0 = (A_01 + A_10)*w0;
-                        const double tmp1 = A_00*w5;
-                        const double tmp2 = A_01*w0;
-                        const double tmp3 = A_10*w0;
-                        const double tmp4 = A_11*w4;
-                        EM_S[INDEX2(0,0,4)]+=tmp4 + tmp0 + tmp1;
-                        EM_S[INDEX2(1,0,4)]+=tmp4 - tmp1 + tmp3 - tmp2;
-                        EM_S[INDEX2(2,0,4)]+=tmp2 - tmp3 - tmp4 + tmp1;
-                        EM_S[INDEX2(3,0,4)]+=-tmp1 - tmp4 - tmp0;
-                        EM_S[INDEX2(0,1,4)]+=tmp4 - tmp1 + tmp2 - tmp3;
-                        EM_S[INDEX2(1,1,4)]+=tmp4 + tmp1 - tmp0;
-                        EM_S[INDEX2(2,1,4)]+=-tmp1 + tmp0 - tmp4;
-                        EM_S[INDEX2(3,1,4)]+=-tmp4 + tmp1 + tmp3 - tmp2;
-                        EM_S[INDEX2(0,2,4)]+=-tmp4 + tmp1 + tmp3 - tmp2;
-                        EM_S[INDEX2(1,2,4)]+=-tmp1 + tmp0 - tmp4;
-                        EM_S[INDEX2(2,2,4)]+=tmp4 + tmp1 - tmp0;
-                        EM_S[INDEX2(3,2,4)]+=tmp4 - tmp1 + tmp2 - tmp3;
-                        EM_S[INDEX2(0,3,4)]+=-tmp1 - tmp4 - tmp0;
-                        EM_S[INDEX2(1,3,4)]+=tmp2 - tmp3 - tmp4 + tmp1;
-                        EM_S[INDEX2(2,3,4)]+=tmp4 - tmp1 + tmp3 - tmp2;
-                        EM_S[INDEX2(3,3,4)]+=tmp4 + tmp0 + tmp1;
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(k1);
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w1;
+                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,2,0,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,0,2,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = tmp0;
+                            }
+                        }
                     }
                     ///////////////
-                    // process B //
+                    // process y //
                     ///////////////
-                    if (!B.isEmpty()) {
-                        addEM_S=true;
-                        const double* B_p=B.getSampleDataRO(e);
-                        const double tmp0 = B_p[0]*w2;
-                        const double tmp1 = B_p[1]*w1;
-                        EM_S[INDEX2(0,0,4)]+=-tmp0 - tmp1;
-                        EM_S[INDEX2(1,0,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(2,0,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(3,0,4)]+= tmp0 + tmp1;
-                        EM_S[INDEX2(0,1,4)]+=-tmp0 - tmp1;
-                        EM_S[INDEX2(1,1,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(2,1,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(3,1,4)]+= tmp0 + tmp1;
-                        EM_S[INDEX2(0,2,4)]+=-tmp0 - tmp1;
-                        EM_S[INDEX2(1,2,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(2,2,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(3,2,4)]+= tmp0 + tmp1;
-                        EM_S[INDEX2(0,3,4)]+=-tmp0 - tmp1;
-                        EM_S[INDEX2(1,3,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(2,3,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(3,3,4)]+= tmp0 + tmp1;
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(k1);
+                        for (index_t k=0; k<numEq; k++) {
+                            EM_F[INDEX2(k,0,numEq)] = 2*w1*y_p[k];
+                            EM_F[INDEX2(k,2,numEq)] = 2*w1*y_p[k];
+                        }
                     }
+                    const index_t firstNode=m_NN[0]*k1;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
+                }
+            } // end colouring
+        }
+
+        if (domain->m_faceOffset[1] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    const index_t e = domain->m_faceOffset[1]+k1;
                     ///////////////
-                    // process C //
+                    // process d //
                     ///////////////
-                    if (!C.isEmpty()) {
-                        addEM_S=true;
-                        const double* C_p=C.getSampleDataRO(e);
-                        const double tmp0 = C_p[0]*w2;
-                        const double tmp1 = C_p[1]*w1;
-                        EM_S[INDEX2(0,0,4)]+=-tmp1 - tmp0;
-                        EM_S[INDEX2(1,0,4)]+=-tmp1 - tmp0;
-                        EM_S[INDEX2(2,0,4)]+=-tmp1 - tmp0;
-                        EM_S[INDEX2(3,0,4)]+=-tmp1 - tmp0;
-                        EM_S[INDEX2(0,1,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(1,1,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(2,1,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(3,1,4)]+= tmp0 - tmp1;
-                        EM_S[INDEX2(0,2,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(1,2,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(2,2,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(3,2,4)]+= tmp1 - tmp0;
-                        EM_S[INDEX2(0,3,4)]+= tmp0 + tmp1;
-                        EM_S[INDEX2(1,3,4)]+= tmp0 + tmp1;
-                        EM_S[INDEX2(2,3,4)]+= tmp0 + tmp1;
-                        EM_S[INDEX2(3,3,4)]+= tmp0 + tmp1;
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w1;
+                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,3,1,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,1,3,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = tmp0;
+                            }
+                        }
                     }
                     ///////////////
-                    // process D //
+                    // process y //
                     ///////////////
-                    if (!D.isEmpty()) {
-                        addEM_S=true;
-                        const double* D_p=D.getSampleDataRO(e);
-                        EM_S[INDEX2(0,0,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(1,0,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(2,0,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(3,0,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(0,1,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(1,1,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(2,1,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(3,1,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(0,2,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(1,2,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(2,2,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(3,2,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(0,3,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(1,3,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(2,3,4)]+=D_p[0]*w3;
-                        EM_S[INDEX2(3,3,4)]+=D_p[0]*w3;
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            EM_F[INDEX2(k,1,numEq)] = 2*w1*y_p[k];
+                            EM_F[INDEX2(k,3,numEq)] = 2*w1*y_p[k];
+                        }
                     }
+                    const index_t firstNode=m_NN[0]*(k1+1)-2;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
+                }
+            } // end colouring
+        }
+
+        if (domain->m_faceOffset[2] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
+            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
+#pragma omp for
+                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
+                    const index_t e = domain->m_faceOffset[2]+k0;
                     ///////////////
-                    // process X //
+                    // process d //
                     ///////////////
-                    if (!X.isEmpty()) {
-                        addEM_F=true;
-                        const double* X_p=X.getSampleDataRO(e);
-                        const double wX0 = 4*X_p[0]*w2;
-                        const double wX1 = 4*X_p[1]*w1;
-                        EM_F[0]+=-wX0 - wX1;
-                        EM_F[1]+=-wX1 + wX0;
-                        EM_F[2]+=-wX0 + wX1;
-                        EM_F[3]+= wX0 + wX1;
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w0;
+                                EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,1,0,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,0,1,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = tmp0;
+                            }
+                        }
                     }
                     ///////////////
-                    // process Y //
+                    // process y //
                     ///////////////
-                    if (!Y.isEmpty()) {
-                        addEM_F=true;
-                        const double* Y_p=Y.getSampleDataRO(e);
-                        EM_F[0]+=4*Y_p[0]*w3;
-                        EM_F[1]+=4*Y_p[0]*w3;
-                        EM_F[2]+=4*Y_p[0]*w3;
-                        EM_F[3]+=4*Y_p[0]*w3;
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            EM_F[INDEX2(k,0,numEq)] = 2*w0*y_p[k];
+                            EM_F[INDEX2(k,1,numEq)] = 2*w0*y_p[k];
+                        }
                     }
+                    const index_t firstNode=k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
+                }
+            } // end colouring
+        }
 
-                    // add to matrix (if addEM_S) and RHS (if addEM_F)
-                    const index_t firstNode=m_NN[0]*k1+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F, firstNode);
-                } // end k0 loop
-            } // end k1 loop
-        } // end of colouring
-    } // end of parallel region
+        if (domain->m_faceOffset[3] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
+            for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
+#pragma omp for
+                for (index_t k0 = k0_0; k0 < NE0; k0+=2) {
+                    const index_t e = domain->m_faceOffset[3]+k0;
+                    ///////////////
+                    // process d //
+                    ///////////////
+                    if (addEM_S) {
+                        const double* d_p=d.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            for (index_t m=0; m<numComp; m++) {
+                                const double tmp0 = d_p[INDEX2(k, m, numEq)]*w0;
+                                EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,3,2,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,2,3,numEq,numComp,4)] = tmp0;
+                                EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = tmp0;
+                            }
+                        }
+                    }
+                    ///////////////
+                    // process y //
+                    ///////////////
+                    if (addEM_F) {
+                        const double* y_p=y.getSampleDataRO(e);
+                        for (index_t k=0; k<numEq; k++) {
+                            EM_F[INDEX2(k,2,numEq)] = 2*w0*y_p[k];
+                            EM_F[INDEX2(k,3,numEq)] = 2*w0*y_p[k];
+                        }
+                    }
+                    const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
+                }
+            } // end colouring
+        }
+    } // end of parallel section
 }
 
 
diff --git a/ripley/src/DefaultAssembler2D.h b/ripley/src/DefaultAssembler2D.h
index 3a05d02..a28e65a 100644
--- a/ripley/src/DefaultAssembler2D.h
+++ b/ripley/src/DefaultAssembler2D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/DefaultAssembler3D.cpp b/ripley/src/DefaultAssembler3D.cpp
index acae774..4de5253 100644
--- a/ripley/src/DefaultAssembler3D.cpp
+++ b/ripley/src/DefaultAssembler3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ripley/DefaultAssembler3D.h>
 #include <ripley/domainhelpers.h>
 
@@ -41,6 +44,10 @@ void DefaultAssembler3D::collateFunctionSpaceTypes(vector<int>& fsTypes,
         fsTypes.push_back(coefs.find("Y")->second.getFunctionSpace().getTypeCode());
 }
 
+/****************************************************************************/
+// wrappers
+/****************************************************************************/
+
 void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
@@ -124,6 +131,9 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
     assemblePDEBoundarySystemReduced(mat, rhs, d, y);
 }
 
+/****************************************************************************/
+// PDE SINGLE
+/****************************************************************************/
 
 void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                                            const Data& A, const Data& B,
@@ -205,25 +215,30 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
+    const bool add_EM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool add_EM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8);
+        vector<double> EM_F(8);
+
         for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
             for (index_t k2=k2_0; k2<NE2; k2+=2) {
                 for (index_t k1=0; k1<NE1; ++k1) {
                     for (index_t k0=0; k0<NE0; ++k0)  {
-                        bool add_EM_S=false;
-                        bool add_EM_F=false;
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                        if (add_EM_S)
+                            fill(EM_S.begin(), EM_S.end(), 0);
+                        if (add_EM_F)
+                            fill(EM_F.begin(), EM_F.end(), 0);
+
                         ///////////////
                         // process A //
                         ///////////////
                         if (!A.isEmpty()) {
-                            add_EM_S = true;
                             const double* A_p = A.getSampleDataRO(e);
                             if (A.actsExpanded()) {
                                 const double A_00_0 = A_p[INDEX3(0,0,0,3,3)];
@@ -809,68 +824,68 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                                 const double tmp508 = w18*(A_12_0 + A_21_6);
                                 const double tmp509 = w4*(-A_12_7 - A_21_1);
                                 EM_S[INDEX2(0,0,8)]+=tmp198 + tmp200 + tmp214 + tmp259 + tmp262 + tmp289 + tmp294 + tmp299 + tmp303 + tmp304 + tmp307 + tmp309 + tmp343 + tmp347 + tmp362 + tmp363 + tmp379 + tmp380 + tmp381 + tmp382 + tmp383 + tmp384 + tmp385 + tmp386;
-                                EM_S[INDEX2(0,1,8)]+=tmp161 + tmp201 + tmp247 + tmp250 + tmp371 + tmp374 + tmp44 + tmp451 + tmp454 + tmp455 + tmp456 + tmp466 + tmp467 + tmp468 + tmp469 + tmp49 + tmp89 + tmp91 + tmp92 + tmp98;
-                                EM_S[INDEX2(0,2,8)]+=tmp135 + tmp236 + tmp238 + tmp240 + tmp242 + tmp244 + tmp39 + tmp41 + tmp432 + tmp436 + tmp440 + tmp441 + tmp490 + tmp491 + tmp492 + tmp493 + tmp61 + tmp68 + tmp70 + tmp71;
-                                EM_S[INDEX2(0,3,8)]+=tmp114 + tmp165 + tmp166 + tmp167 + tmp168 + tmp169 + tmp170 + tmp171 + tmp172 + tmp20 + tmp73 + tmp74 + tmp75 + tmp76 + tmp79 + tmp80;
-                                EM_S[INDEX2(0,4,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp145 + tmp146 + tmp148 + tmp15 + tmp189 + tmp190 + tmp192 + tmp193 + tmp2 + tmp243 + tmp246 + tmp406 + tmp407 + tmp408 + tmp409 + tmp5;
-                                EM_S[INDEX2(0,5,8)]+=tmp174 + tmp176 + tmp184 + tmp24 + tmp260 + tmp267 + tmp339 + tmp340 + tmp341 + tmp342 + tmp344 + tmp345 + tmp416 + tmp417 + tmp506 + tmp507;
-                                EM_S[INDEX2(0,6,8)]+=tmp21 + tmp258 + tmp266 + tmp274 + tmp337 + tmp398 + tmp422 + tmp424 + tmp428 + tmp430 + tmp447 + tmp449 + tmp496 + tmp497 + tmp498 + tmp499;
-                                EM_S[INDEX2(0,7,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113 + tmp38 + tmp87;
                                 EM_S[INDEX2(1,0,8)]+=tmp145 + tmp148 + tmp161 + tmp201 + tmp202 + tmp210 + tmp371 + tmp374 + tmp440 + tmp441 + tmp450 + tmp451 + tmp452 + tmp453 + tmp454 + tmp455 + tmp456 + tmp457 + tmp89 + tmp91;
-                                EM_S[INDEX2(1,1,8)]+=tmp215 + tmp221 + tmp227 + tmp260 + tmp267 + tmp288 + tmp304 + tmp312 + tmp317 + tmp351 + tmp352 + tmp353 + tmp354 + tmp355 + tmp356 + tmp357 + tmp358 + tmp359 + tmp360 + tmp361 + tmp362 + tmp363 + tmp76 + tmp79;
-                                EM_S[INDEX2(1,2,8)]+=tmp166 + tmp169 + tmp172 + tmp196 + tmp197 + tmp198 + tmp199 + tmp20 + tmp200 + tmp21 + tmp73 + tmp74 + tmp75 + tmp77 + tmp80 + tmp82;
-                                EM_S[INDEX2(1,3,8)]+=tmp36 + tmp37 + tmp38 + tmp39 + tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55;
-                                EM_S[INDEX2(1,4,8)]+=tmp176 + tmp24 + tmp269 + tmp274 + tmp339 + tmp340 + tmp342 + tmp343 + tmp344 + tmp347 + tmp394 + tmp395 + tmp416 + tmp417 + tmp418 + tmp419;
-                                EM_S[INDEX2(1,5,8)]+=tmp112 + tmp12 + tmp123 + tmp13 + tmp141 + tmp142 + tmp143 + tmp146 + tmp147 + tmp149 + tmp16 + tmp277 + tmp278 + tmp279 + tmp280 + tmp281 + tmp282 + tmp6 + tmp92 + tmp98;
-                                EM_S[INDEX2(1,6,8)]+=tmp104 + tmp105 + tmp106 + tmp110 + tmp113 + tmp135 + tmp136 + tmp137 + tmp138 + tmp139 + tmp15 + tmp87;
-                                EM_S[INDEX2(1,7,8)]+=tmp114 + tmp184 + tmp225 + tmp232 + tmp329 + tmp330 + tmp332 + tmp334 + tmp335 + tmp337 + tmp338 + tmp421 + tmp464 + tmp465 + tmp504 + tmp505;
                                 EM_S[INDEX2(2,0,8)]+=tmp135 + tmp234 + tmp235 + tmp236 + tmp237 + tmp238 + tmp239 + tmp240 + tmp241 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp39 + tmp41 + tmp44 + tmp49 + tmp61 + tmp71;
-                                EM_S[INDEX2(2,1,8)]+=tmp114 + tmp120 + tmp167 + tmp170 + tmp198 + tmp20 + tmp200 + tmp24 + tmp443 + tmp444 + tmp73 + tmp74 + tmp75 + tmp80 + tmp81 + tmp83;
-                                EM_S[INDEX2(2,2,8)]+=tmp217 + tmp231 + tmp233 + tmp258 + tmp266 + tmp271 + tmp273 + tmp288 + tmp289 + tmp290 + tmp291 + tmp292 + tmp293 + tmp294 + tmp295 + tmp296 + tmp297 + tmp298 + tmp299 + tmp300 + tmp301 + tmp302 + tmp76 + tmp79;
-                                EM_S[INDEX2(2,3,8)]+=tmp101 + tmp156 + tmp157 + tmp204 + tmp205 + tmp368 + tmp371 + tmp372 + tmp374 + tmp375 + tmp377 + tmp437 + tmp438 + tmp439 + tmp440 + tmp441 + tmp442 + tmp85 + tmp87 + tmp99;
-                                EM_S[INDEX2(2,4,8)]+=tmp184 + tmp21 + tmp328 + tmp337 + tmp383 + tmp386 + tmp422 + tmp423 + tmp424 + tmp427 + tmp428 + tmp430 + tmp498 + tmp499 + tmp508 + tmp509;
-                                EM_S[INDEX2(2,5,8)]+=tmp104 + tmp106 + tmp108 + tmp111 + tmp113 + tmp15 + tmp160 + tmp161 + tmp162 + tmp163 + tmp164 + tmp38;
-                                EM_S[INDEX2(2,6,8)]+=tmp10 + tmp112 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131 + tmp132 + tmp133 + tmp134 + tmp14 + tmp3 + tmp68 + tmp70 + tmp9;
-                                EM_S[INDEX2(2,7,8)]+=tmp166 + tmp175 + tmp176 + tmp178 + tmp179 + tmp180 + tmp183 + tmp187 + tmp270 + tmp272 + tmp274 + tmp284 + tmp285 + tmp364 + tmp365 + tmp366;
                                 EM_S[INDEX2(3,0,8)]+=tmp20 + tmp21 + tmp24 + tmp34 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp80 + tmp81 + tmp82 + tmp83;
-                                EM_S[INDEX2(3,1,8)]+=tmp13 + tmp16 + tmp38 + tmp39 + tmp40 + tmp41 + tmp43 + tmp440 + tmp441 + tmp45 + tmp47 + tmp478 + tmp481 + tmp486 + tmp487 + tmp488 + tmp489 + tmp50 + tmp52 + tmp55;
-                                EM_S[INDEX2(3,2,8)]+=tmp101 + tmp14 + tmp204 + tmp205 + tmp367 + tmp368 + tmp369 + tmp370 + tmp371 + tmp372 + tmp373 + tmp374 + tmp375 + tmp376 + tmp377 + tmp378 + tmp44 + tmp49 + tmp87 + tmp9;
-                                EM_S[INDEX2(3,3,8)]+=tmp179 + tmp183 + tmp198 + tmp200 + tmp214 + tmp215 + tmp216 + tmp217 + tmp218 + tmp219 + tmp220 + tmp221 + tmp222 + tmp223 + tmp224 + tmp225 + tmp226 + tmp227 + tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233;
-                                EM_S[INDEX2(3,4,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp135 + tmp137 + tmp139 + tmp160 + tmp161 + tmp164 + tmp471 + tmp473;
-                                EM_S[INDEX2(3,5,8)]+=tmp114 + tmp274 + tmp312 + tmp317 + tmp329 + tmp332 + tmp335 + tmp337 + tmp338 + tmp399 + tmp401 + tmp446 + tmp462 + tmp463 + tmp464 + tmp465;
-                                EM_S[INDEX2(3,6,8)]+=tmp166 + tmp175 + tmp176 + tmp177 + tmp178 + tmp180 + tmp181 + tmp184 + tmp187 + tmp271 + tmp273 + tmp283 + tmp284 + tmp285 + tmp286 + tmp287;
-                                EM_S[INDEX2(3,7,8)]+=tmp1 + tmp10 + tmp11 + tmp12 + tmp15 + tmp152 + tmp153 + tmp154 + tmp155 + tmp156 + tmp157 + tmp158 + tmp159 + tmp17 + tmp3 + tmp4 + tmp51 + tmp54 + tmp6 + tmp7;
                                 EM_S[INDEX2(4,0,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp146 + tmp15 + tmp153 + tmp154 + tmp188 + tmp189 + tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp68 + tmp70 + tmp92 + tmp98;
-                                EM_S[INDEX2(4,1,8)]+=tmp166 + tmp176 + tmp184 + tmp283 + tmp339 + tmp340 + tmp341 + tmp342 + tmp343 + tmp344 + tmp345 + tmp346 + tmp347 + tmp348 + tmp349 + tmp350;
-                                EM_S[INDEX2(4,2,8)]+=tmp114 + tmp274 + tmp337 + tmp383 + tmp386 + tmp422 + tmp424 + tmp426 + tmp428 + tmp429 + tmp430 + tmp445 + tmp446 + tmp447 + tmp448 + tmp449;
-                                EM_S[INDEX2(4,3,8)]+=tmp104 + tmp106 + tmp107 + tmp109 + tmp112 + tmp113 + tmp135 + tmp161 + tmp482 + tmp483 + tmp484 + tmp485;
-                                EM_S[INDEX2(4,4,8)]+=tmp118 + tmp121 + tmp214 + tmp215 + tmp216 + tmp217 + tmp220 + tmp222 + tmp253 + tmp254 + tmp255 + tmp256 + tmp257 + tmp258 + tmp259 + tmp260 + tmp261 + tmp262 + tmp263 + tmp264 + tmp265 + tmp266 + tmp267 + tmp268;
-                                EM_S[INDEX2(4,5,8)]+=tmp100 + tmp101 + tmp145 + tmp148 + tmp369 + tmp376 + tmp402 + tmp403 + tmp404 + tmp405 + tmp60 + tmp65 + tmp84 + tmp87 + tmp88 + tmp89 + tmp91 + tmp95 + tmp96 + tmp97;
-                                EM_S[INDEX2(4,6,8)]+=tmp243 + tmp246 + tmp38 + tmp43 + tmp476 + tmp477 + tmp478 + tmp479 + tmp480 + tmp481 + tmp57 + tmp58 + tmp61 + tmp63 + tmp64 + tmp66 + tmp69 + tmp71 + tmp90 + tmp94;
-                                EM_S[INDEX2(4,7,8)]+=tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
                                 EM_S[INDEX2(5,0,8)]+=tmp166 + tmp176 + tmp260 + tmp267 + tmp274 + tmp339 + tmp340 + tmp342 + tmp344 + tmp346 + tmp348 + tmp365 + tmp393 + tmp394 + tmp395 + tmp396;
-                                EM_S[INDEX2(5,1,8)]+=tmp112 + tmp12 + tmp123 + tmp124 + tmp126 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147 + tmp148 + tmp149 + tmp150 + tmp151 + tmp51 + tmp54 + tmp6;
-                                EM_S[INDEX2(5,2,8)]+=tmp104 + tmp106 + tmp113 + tmp136 + tmp138 + tmp15 + tmp161 + tmp38 + tmp472 + tmp475 + tmp482 + tmp483;
-                                EM_S[INDEX2(5,3,8)]+=tmp184 + tmp21 + tmp312 + tmp317 + tmp327 + tmp328 + tmp329 + tmp330 + tmp331 + tmp332 + tmp333 + tmp334 + tmp335 + tmp336 + tmp337 + tmp338;
-                                EM_S[INDEX2(5,4,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91 + tmp92 + tmp93 + tmp94 + tmp95 + tmp96 + tmp97 + tmp98 + tmp99;
-                                EM_S[INDEX2(5,5,8)]+=tmp217 + tmp225 + tmp232 + tmp26 + tmp265 + tmp268 + tmp288 + tmp289 + tmp29 + tmp290 + tmp293 + tmp295 + tmp308 + tmp313 + tmp343 + tmp347 + tmp358 + tmp359 + tmp410 + tmp411 + tmp412 + tmp413 + tmp414 + tmp415;
-                                EM_S[INDEX2(5,6,8)]+=tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp20 + tmp22 + tmp24 + tmp25 + tmp28 + tmp30 + tmp32 + tmp35;
-                                EM_S[INDEX2(5,7,8)]+=tmp13 + tmp135 + tmp16 + tmp237 + tmp238 + tmp245 + tmp319 + tmp320 + tmp321 + tmp322 + tmp323 + tmp324 + tmp325 + tmp326 + tmp45 + tmp55 + tmp57 + tmp60 + tmp64 + tmp65;
                                 EM_S[INDEX2(6,0,8)]+=tmp114 + tmp184 + tmp258 + tmp266 + tmp337 + tmp420 + tmp421 + tmp422 + tmp423 + tmp424 + tmp425 + tmp426 + tmp427 + tmp428 + tmp429 + tmp430;
-                                EM_S[INDEX2(6,1,8)]+=tmp104 + tmp106 + tmp113 + tmp135 + tmp15 + tmp162 + tmp163 + tmp470 + tmp474 + tmp484 + tmp485 + tmp87;
-                                EM_S[INDEX2(6,2,8)]+=tmp10 + tmp112 + tmp123 + tmp125 + tmp127 + tmp128 + tmp130 + tmp131 + tmp132 + tmp156 + tmp157 + tmp243 + tmp246 + tmp278 + tmp279 + tmp3 + tmp500 + tmp501 + tmp502 + tmp503;
-                                EM_S[INDEX2(6,3,8)]+=tmp175 + tmp176 + tmp178 + tmp180 + tmp182 + tmp185 + tmp187 + tmp24 + tmp269 + tmp270 + tmp271 + tmp272 + tmp273 + tmp274 + tmp275 + tmp276;
-                                EM_S[INDEX2(6,4,8)]+=tmp38 + tmp42 + tmp43 + tmp53 + tmp56 + tmp57 + tmp58 + tmp59 + tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65 + tmp66 + tmp67 + tmp68 + tmp69 + tmp70 + tmp71;
-                                EM_S[INDEX2(6,5,8)]+=tmp118 + tmp121 + tmp166 + tmp199 + tmp20 + tmp21 + tmp22 + tmp25 + tmp27 + tmp28 + tmp30 + tmp33 + tmp458 + tmp459 + tmp460 + tmp461;
-                                EM_S[INDEX2(6,6,8)]+=tmp179 + tmp183 + tmp215 + tmp255 + tmp26 + tmp261 + tmp288 + tmp29 + tmp298 + tmp300 + tmp304 + tmp316 + tmp318 + tmp351 + tmp354 + tmp355 + tmp383 + tmp386 + tmp387 + tmp388 + tmp389 + tmp390 + tmp391 + tmp392;
-                                EM_S[INDEX2(6,7,8)]+=tmp100 + tmp14 + tmp161 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp208 + tmp209 + tmp210 + tmp211 + tmp212 + tmp213 + tmp88 + tmp9 + tmp90 + tmp94;
                                 EM_S[INDEX2(7,0,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp38 + tmp470 + tmp471 + tmp472 + tmp473 + tmp474 + tmp475 + tmp87;
+                                EM_S[INDEX2(0,1,8)]+=tmp161 + tmp201 + tmp247 + tmp250 + tmp371 + tmp374 + tmp44 + tmp451 + tmp454 + tmp455 + tmp456 + tmp466 + tmp467 + tmp468 + tmp469 + tmp49 + tmp89 + tmp91 + tmp92 + tmp98;
+                                EM_S[INDEX2(1,1,8)]+=tmp215 + tmp221 + tmp227 + tmp260 + tmp267 + tmp288 + tmp304 + tmp312 + tmp317 + tmp351 + tmp352 + tmp353 + tmp354 + tmp355 + tmp356 + tmp357 + tmp358 + tmp359 + tmp360 + tmp361 + tmp362 + tmp363 + tmp76 + tmp79;
+                                EM_S[INDEX2(2,1,8)]+=tmp114 + tmp120 + tmp167 + tmp170 + tmp198 + tmp20 + tmp200 + tmp24 + tmp443 + tmp444 + tmp73 + tmp74 + tmp75 + tmp80 + tmp81 + tmp83;
+                                EM_S[INDEX2(3,1,8)]+=tmp13 + tmp16 + tmp38 + tmp39 + tmp40 + tmp41 + tmp43 + tmp440 + tmp441 + tmp45 + tmp47 + tmp478 + tmp481 + tmp486 + tmp487 + tmp488 + tmp489 + tmp50 + tmp52 + tmp55;
+                                EM_S[INDEX2(4,1,8)]+=tmp166 + tmp176 + tmp184 + tmp283 + tmp339 + tmp340 + tmp341 + tmp342 + tmp343 + tmp344 + tmp345 + tmp346 + tmp347 + tmp348 + tmp349 + tmp350;
+                                EM_S[INDEX2(5,1,8)]+=tmp112 + tmp12 + tmp123 + tmp124 + tmp126 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147 + tmp148 + tmp149 + tmp150 + tmp151 + tmp51 + tmp54 + tmp6;
+                                EM_S[INDEX2(6,1,8)]+=tmp104 + tmp106 + tmp113 + tmp135 + tmp15 + tmp162 + tmp163 + tmp470 + tmp474 + tmp484 + tmp485 + tmp87;
                                 EM_S[INDEX2(7,1,8)]+=tmp21 + tmp225 + tmp232 + tmp274 + tmp329 + tmp332 + tmp333 + tmp335 + tmp336 + tmp337 + tmp338 + tmp397 + tmp398 + tmp399 + tmp400 + tmp401;
+                                EM_S[INDEX2(0,2,8)]+=tmp135 + tmp236 + tmp238 + tmp240 + tmp242 + tmp244 + tmp39 + tmp41 + tmp432 + tmp436 + tmp440 + tmp441 + tmp490 + tmp491 + tmp492 + tmp493 + tmp61 + tmp68 + tmp70 + tmp71;
+                                EM_S[INDEX2(1,2,8)]+=tmp166 + tmp169 + tmp172 + tmp196 + tmp197 + tmp198 + tmp199 + tmp20 + tmp200 + tmp21 + tmp73 + tmp74 + tmp75 + tmp77 + tmp80 + tmp82;
+                                EM_S[INDEX2(2,2,8)]+=tmp217 + tmp231 + tmp233 + tmp258 + tmp266 + tmp271 + tmp273 + tmp288 + tmp289 + tmp290 + tmp291 + tmp292 + tmp293 + tmp294 + tmp295 + tmp296 + tmp297 + tmp298 + tmp299 + tmp300 + tmp301 + tmp302 + tmp76 + tmp79;
+                                EM_S[INDEX2(3,2,8)]+=tmp101 + tmp14 + tmp204 + tmp205 + tmp367 + tmp368 + tmp369 + tmp370 + tmp371 + tmp372 + tmp373 + tmp374 + tmp375 + tmp376 + tmp377 + tmp378 + tmp44 + tmp49 + tmp87 + tmp9;
+                                EM_S[INDEX2(4,2,8)]+=tmp114 + tmp274 + tmp337 + tmp383 + tmp386 + tmp422 + tmp424 + tmp426 + tmp428 + tmp429 + tmp430 + tmp445 + tmp446 + tmp447 + tmp448 + tmp449;
+                                EM_S[INDEX2(5,2,8)]+=tmp104 + tmp106 + tmp113 + tmp136 + tmp138 + tmp15 + tmp161 + tmp38 + tmp472 + tmp475 + tmp482 + tmp483;
+                                EM_S[INDEX2(6,2,8)]+=tmp10 + tmp112 + tmp123 + tmp125 + tmp127 + tmp128 + tmp130 + tmp131 + tmp132 + tmp156 + tmp157 + tmp243 + tmp246 + tmp278 + tmp279 + tmp3 + tmp500 + tmp501 + tmp502 + tmp503;
                                 EM_S[INDEX2(7,2,8)]+=tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179 + tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp24;
+                                EM_S[INDEX2(0,3,8)]+=tmp114 + tmp165 + tmp166 + tmp167 + tmp168 + tmp169 + tmp170 + tmp171 + tmp172 + tmp20 + tmp73 + tmp74 + tmp75 + tmp76 + tmp79 + tmp80;
+                                EM_S[INDEX2(1,3,8)]+=tmp36 + tmp37 + tmp38 + tmp39 + tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55;
+                                EM_S[INDEX2(2,3,8)]+=tmp101 + tmp156 + tmp157 + tmp204 + tmp205 + tmp368 + tmp371 + tmp372 + tmp374 + tmp375 + tmp377 + tmp437 + tmp438 + tmp439 + tmp440 + tmp441 + tmp442 + tmp85 + tmp87 + tmp99;
+                                EM_S[INDEX2(3,3,8)]+=tmp179 + tmp183 + tmp198 + tmp200 + tmp214 + tmp215 + tmp216 + tmp217 + tmp218 + tmp219 + tmp220 + tmp221 + tmp222 + tmp223 + tmp224 + tmp225 + tmp226 + tmp227 + tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233;
+                                EM_S[INDEX2(4,3,8)]+=tmp104 + tmp106 + tmp107 + tmp109 + tmp112 + tmp113 + tmp135 + tmp161 + tmp482 + tmp483 + tmp484 + tmp485;
+                                EM_S[INDEX2(5,3,8)]+=tmp184 + tmp21 + tmp312 + tmp317 + tmp327 + tmp328 + tmp329 + tmp330 + tmp331 + tmp332 + tmp333 + tmp334 + tmp335 + tmp336 + tmp337 + tmp338;
+                                EM_S[INDEX2(6,3,8)]+=tmp175 + tmp176 + tmp178 + tmp180 + tmp182 + tmp185 + tmp187 + tmp24 + tmp269 + tmp270 + tmp271 + tmp272 + tmp273 + tmp274 + tmp275 + tmp276;
                                 EM_S[INDEX2(7,3,8)]+=tmp0 + tmp1 + tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
+                                EM_S[INDEX2(0,4,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp145 + tmp146 + tmp148 + tmp15 + tmp189 + tmp190 + tmp192 + tmp193 + tmp2 + tmp243 + tmp246 + tmp406 + tmp407 + tmp408 + tmp409 + tmp5;
+                                EM_S[INDEX2(1,4,8)]+=tmp176 + tmp24 + tmp269 + tmp274 + tmp339 + tmp340 + tmp342 + tmp343 + tmp344 + tmp347 + tmp394 + tmp395 + tmp416 + tmp417 + tmp418 + tmp419;
+                                EM_S[INDEX2(2,4,8)]+=tmp184 + tmp21 + tmp328 + tmp337 + tmp383 + tmp386 + tmp422 + tmp423 + tmp424 + tmp427 + tmp428 + tmp430 + tmp498 + tmp499 + tmp508 + tmp509;
+                                EM_S[INDEX2(3,4,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp135 + tmp137 + tmp139 + tmp160 + tmp161 + tmp164 + tmp471 + tmp473;
+                                EM_S[INDEX2(4,4,8)]+=tmp118 + tmp121 + tmp214 + tmp215 + tmp216 + tmp217 + tmp220 + tmp222 + tmp253 + tmp254 + tmp255 + tmp256 + tmp257 + tmp258 + tmp259 + tmp260 + tmp261 + tmp262 + tmp263 + tmp264 + tmp265 + tmp266 + tmp267 + tmp268;
+                                EM_S[INDEX2(5,4,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91 + tmp92 + tmp93 + tmp94 + tmp95 + tmp96 + tmp97 + tmp98 + tmp99;
+                                EM_S[INDEX2(6,4,8)]+=tmp38 + tmp42 + tmp43 + tmp53 + tmp56 + tmp57 + tmp58 + tmp59 + tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65 + tmp66 + tmp67 + tmp68 + tmp69 + tmp70 + tmp71;
                                 EM_S[INDEX2(7,4,8)]+=tmp114 + tmp117 + tmp119 + tmp166 + tmp171 + tmp20 + tmp22 + tmp25 + tmp26 + tmp28 + tmp29 + tmp30 + tmp460 + tmp461 + tmp494 + tmp495;
+                                EM_S[INDEX2(0,5,8)]+=tmp174 + tmp176 + tmp184 + tmp24 + tmp260 + tmp267 + tmp339 + tmp340 + tmp341 + tmp342 + tmp344 + tmp345 + tmp416 + tmp417 + tmp506 + tmp507;
+                                EM_S[INDEX2(1,5,8)]+=tmp112 + tmp12 + tmp123 + tmp13 + tmp141 + tmp142 + tmp143 + tmp146 + tmp147 + tmp149 + tmp16 + tmp277 + tmp278 + tmp279 + tmp280 + tmp281 + tmp282 + tmp6 + tmp92 + tmp98;
+                                EM_S[INDEX2(2,5,8)]+=tmp104 + tmp106 + tmp108 + tmp111 + tmp113 + tmp15 + tmp160 + tmp161 + tmp162 + tmp163 + tmp164 + tmp38;
+                                EM_S[INDEX2(3,5,8)]+=tmp114 + tmp274 + tmp312 + tmp317 + tmp329 + tmp332 + tmp335 + tmp337 + tmp338 + tmp399 + tmp401 + tmp446 + tmp462 + tmp463 + tmp464 + tmp465;
+                                EM_S[INDEX2(4,5,8)]+=tmp100 + tmp101 + tmp145 + tmp148 + tmp369 + tmp376 + tmp402 + tmp403 + tmp404 + tmp405 + tmp60 + tmp65 + tmp84 + tmp87 + tmp88 + tmp89 + tmp91 + tmp95 + tmp96 + tmp97;
+                                EM_S[INDEX2(5,5,8)]+=tmp217 + tmp225 + tmp232 + tmp26 + tmp265 + tmp268 + tmp288 + tmp289 + tmp29 + tmp290 + tmp293 + tmp295 + tmp308 + tmp313 + tmp343 + tmp347 + tmp358 + tmp359 + tmp410 + tmp411 + tmp412 + tmp413 + tmp414 + tmp415;
+                                EM_S[INDEX2(6,5,8)]+=tmp118 + tmp121 + tmp166 + tmp199 + tmp20 + tmp21 + tmp22 + tmp25 + tmp27 + tmp28 + tmp30 + tmp33 + tmp458 + tmp459 + tmp460 + tmp461;
                                 EM_S[INDEX2(7,5,8)]+=tmp135 + tmp238 + tmp320 + tmp324 + tmp325 + tmp326 + tmp431 + tmp432 + tmp433 + tmp434 + tmp435 + tmp436 + tmp45 + tmp51 + tmp54 + tmp55 + tmp57 + tmp64 + tmp90 + tmp94;
+                                EM_S[INDEX2(0,6,8)]+=tmp21 + tmp258 + tmp266 + tmp274 + tmp337 + tmp398 + tmp422 + tmp424 + tmp428 + tmp430 + tmp447 + tmp449 + tmp496 + tmp497 + tmp498 + tmp499;
+                                EM_S[INDEX2(1,6,8)]+=tmp104 + tmp105 + tmp106 + tmp110 + tmp113 + tmp135 + tmp136 + tmp137 + tmp138 + tmp139 + tmp15 + tmp87;
+                                EM_S[INDEX2(2,6,8)]+=tmp10 + tmp112 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131 + tmp132 + tmp133 + tmp134 + tmp14 + tmp3 + tmp68 + tmp70 + tmp9;
+                                EM_S[INDEX2(3,6,8)]+=tmp166 + tmp175 + tmp176 + tmp177 + tmp178 + tmp180 + tmp181 + tmp184 + tmp187 + tmp271 + tmp273 + tmp283 + tmp284 + tmp285 + tmp286 + tmp287;
+                                EM_S[INDEX2(4,6,8)]+=tmp243 + tmp246 + tmp38 + tmp43 + tmp476 + tmp477 + tmp478 + tmp479 + tmp480 + tmp481 + tmp57 + tmp58 + tmp61 + tmp63 + tmp64 + tmp66 + tmp69 + tmp71 + tmp90 + tmp94;
+                                EM_S[INDEX2(5,6,8)]+=tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp20 + tmp22 + tmp24 + tmp25 + tmp28 + tmp30 + tmp32 + tmp35;
+                                EM_S[INDEX2(6,6,8)]+=tmp179 + tmp183 + tmp215 + tmp255 + tmp26 + tmp261 + tmp288 + tmp29 + tmp298 + tmp300 + tmp304 + tmp316 + tmp318 + tmp351 + tmp354 + tmp355 + tmp383 + tmp386 + tmp387 + tmp388 + tmp389 + tmp390 + tmp391 + tmp392;
                                 EM_S[INDEX2(7,6,8)]+=tmp100 + tmp156 + tmp157 + tmp161 + tmp201 + tmp204 + tmp205 + tmp207 + tmp208 + tmp209 + tmp211 + tmp247 + tmp248 + tmp249 + tmp250 + tmp251 + tmp252 + tmp60 + tmp65 + tmp88;
+                                EM_S[INDEX2(0,7,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113 + tmp38 + tmp87;
+                                EM_S[INDEX2(1,7,8)]+=tmp114 + tmp184 + tmp225 + tmp232 + tmp329 + tmp330 + tmp332 + tmp334 + tmp335 + tmp337 + tmp338 + tmp421 + tmp464 + tmp465 + tmp504 + tmp505;
+                                EM_S[INDEX2(2,7,8)]+=tmp166 + tmp175 + tmp176 + tmp178 + tmp179 + tmp180 + tmp183 + tmp187 + tmp270 + tmp272 + tmp274 + tmp284 + tmp285 + tmp364 + tmp365 + tmp366;
+                                EM_S[INDEX2(3,7,8)]+=tmp1 + tmp10 + tmp11 + tmp12 + tmp15 + tmp152 + tmp153 + tmp154 + tmp155 + tmp156 + tmp157 + tmp158 + tmp159 + tmp17 + tmp3 + tmp4 + tmp51 + tmp54 + tmp6 + tmp7;
+                                EM_S[INDEX2(4,7,8)]+=tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
+                                EM_S[INDEX2(5,7,8)]+=tmp13 + tmp135 + tmp16 + tmp237 + tmp238 + tmp245 + tmp319 + tmp320 + tmp321 + tmp322 + tmp323 + tmp324 + tmp325 + tmp326 + tmp45 + tmp55 + tmp57 + tmp60 + tmp64 + tmp65;
+                                EM_S[INDEX2(6,7,8)]+=tmp100 + tmp14 + tmp161 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp208 + tmp209 + tmp210 + tmp211 + tmp212 + tmp213 + tmp88 + tmp9 + tmp90 + tmp94;
                                 EM_S[INDEX2(7,7,8)]+=tmp118 + tmp121 + tmp214 + tmp226 + tmp228 + tmp271 + tmp273 + tmp289 + tmp303 + tmp304 + tmp305 + tmp306 + tmp307 + tmp308 + tmp309 + tmp310 + tmp311 + tmp312 + tmp313 + tmp314 + tmp315 + tmp316 + tmp317 + tmp318;
                             } else { // constant data
                                 const double Aw00 = 8*A_p[INDEX2(0,0,3)]*w27;
@@ -895,68 +910,68 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                                 const double tmp10 = -Aw12 - Aw21;
                                 const double tmp11 = -Aw12 + Aw21;
                                 EM_S[INDEX2(0,0,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp4 + 2*tmp10;
-                                EM_S[INDEX2(0,1,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp10 + 2*tmp1 + 2*tmp5;
-                                EM_S[INDEX2(0,2,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp3 + tmp4 + 2*tmp11;
-                                EM_S[INDEX2(0,3,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + tmp11 + 2*tmp2;
-                                EM_S[INDEX2(0,4,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + 2*tmp9 + tmp0;
-                                EM_S[INDEX2(0,5,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp6 + tmp1 + tmp9;
-                                EM_S[INDEX2(0,6,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp8 + tmp3 + tmp7;
-                                EM_S[INDEX2(0,7,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp2 + tmp6;
                                 EM_S[INDEX2(1,0,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + 2*tmp3 + tmp10;
-                                EM_S[INDEX2(1,1,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp6 + 2*tmp10 + 2*tmp2;
-                                EM_S[INDEX2(1,2,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 + tmp11 + tmp7;
-                                EM_S[INDEX2(1,3,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + tmp6 + 2*tmp11 + 2*tmp1;
-                                EM_S[INDEX2(1,4,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp4 + tmp3 + tmp9;
-                                EM_S[INDEX2(1,5,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp9 + tmp2 + 2*tmp5;
-                                EM_S[INDEX2(1,6,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp4 + tmp0;
-                                EM_S[INDEX2(1,7,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp1 + 2*tmp8;
                                 EM_S[INDEX2(2,0,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + tmp4 + 2*tmp1;
-                                EM_S[INDEX2(2,1,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + 2*tmp0 + tmp9;
-                                EM_S[INDEX2(2,2,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp8 + 2*tmp4 + 2*tmp2;
-                                EM_S[INDEX2(2,3,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp8 + 2*tmp3 + 2*tmp5;
-                                EM_S[INDEX2(2,4,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 + 2*tmp10 + tmp7;
-                                EM_S[INDEX2(2,5,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp10 + tmp0 + tmp6;
-                                EM_S[INDEX2(2,6,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + tmp2 + 2*tmp11;
-                                EM_S[INDEX2(2,7,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + 2*tmp6 + tmp3;
                                 EM_S[INDEX2(3,0,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp7 + tmp9 + 2*tmp2;
-                                EM_S[INDEX2(3,1,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + 2*tmp3 + tmp6;
-                                EM_S[INDEX2(3,2,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + tmp8 + 2*tmp1;
-                                EM_S[INDEX2(3,3,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp6 + 2*tmp8;
-                                EM_S[INDEX2(3,4,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp2 + tmp4 + tmp10;
-                                EM_S[INDEX2(3,5,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp3 + 2*tmp10;
-                                EM_S[INDEX2(3,6,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + tmp1 + 2*tmp4;
-                                EM_S[INDEX2(3,7,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 + 2*tmp11 + 2*tmp5;
                                 EM_S[INDEX2(4,0,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 + 2*tmp11 + 2*tmp5;
-                                EM_S[INDEX2(4,1,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + tmp1 + 2*tmp4;
-                                EM_S[INDEX2(4,2,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp3 + 2*tmp10;
-                                EM_S[INDEX2(4,3,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp2 + tmp4 + tmp10;
-                                EM_S[INDEX2(4,4,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp6 + 2*tmp8;
-                                EM_S[INDEX2(4,5,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + tmp8 + 2*tmp1;
-                                EM_S[INDEX2(4,6,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + 2*tmp3 + tmp6;
-                                EM_S[INDEX2(4,7,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp7 + tmp9 + 2*tmp2;
                                 EM_S[INDEX2(5,0,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + 2*tmp6 + tmp3;
-                                EM_S[INDEX2(5,1,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + tmp2 + 2*tmp11;
-                                EM_S[INDEX2(5,2,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp10 + tmp0 + tmp6;
-                                EM_S[INDEX2(5,3,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 + 2*tmp10 + tmp7;
-                                EM_S[INDEX2(5,4,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp8 + 2*tmp3 + 2*tmp5;
-                                EM_S[INDEX2(5,5,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp8 + 2*tmp4 + 2*tmp2;
-                                EM_S[INDEX2(5,6,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + 2*tmp0 + tmp9;
-                                EM_S[INDEX2(5,7,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + tmp4 + 2*tmp1;
                                 EM_S[INDEX2(6,0,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp1 + 2*tmp8;
-                                EM_S[INDEX2(6,1,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp4 + tmp0;
-                                EM_S[INDEX2(6,2,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp9 + tmp2 + 2*tmp5;
-                                EM_S[INDEX2(6,3,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp4 + tmp3 + tmp9;
-                                EM_S[INDEX2(6,4,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + tmp6 + 2*tmp11 + 2*tmp1;
-                                EM_S[INDEX2(6,5,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 + tmp11 + tmp7;
-                                EM_S[INDEX2(6,6,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp6 + 2*tmp10 + 2*tmp2;
-                                EM_S[INDEX2(6,7,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + 2*tmp3 + tmp10;
                                 EM_S[INDEX2(7,0,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp2 + tmp6;
+                                EM_S[INDEX2(0,1,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp10 + 2*tmp1 + 2*tmp5;
+                                EM_S[INDEX2(1,1,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp6 + 2*tmp10 + 2*tmp2;
+                                EM_S[INDEX2(2,1,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + 2*tmp0 + tmp9;
+                                EM_S[INDEX2(3,1,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + 2*tmp3 + tmp6;
+                                EM_S[INDEX2(4,1,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + tmp1 + 2*tmp4;
+                                EM_S[INDEX2(5,1,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + tmp2 + 2*tmp11;
+                                EM_S[INDEX2(6,1,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp4 + tmp0;
                                 EM_S[INDEX2(7,1,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp8 + tmp3 + tmp7;
+                                EM_S[INDEX2(0,2,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp3 + tmp4 + 2*tmp11;
+                                EM_S[INDEX2(1,2,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 + tmp11 + tmp7;
+                                EM_S[INDEX2(2,2,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp8 + 2*tmp4 + 2*tmp2;
+                                EM_S[INDEX2(3,2,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + tmp8 + 2*tmp1;
+                                EM_S[INDEX2(4,2,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp3 + 2*tmp10;
+                                EM_S[INDEX2(5,2,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp10 + tmp0 + tmp6;
+                                EM_S[INDEX2(6,2,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp9 + tmp2 + 2*tmp5;
                                 EM_S[INDEX2(7,2,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp6 + tmp1 + tmp9;
+                                EM_S[INDEX2(0,3,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + tmp11 + 2*tmp2;
+                                EM_S[INDEX2(1,3,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + tmp6 + 2*tmp11 + 2*tmp1;
+                                EM_S[INDEX2(2,3,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp8 + 2*tmp3 + 2*tmp5;
+                                EM_S[INDEX2(3,3,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp6 + 2*tmp8;
+                                EM_S[INDEX2(4,3,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp2 + tmp4 + tmp10;
+                                EM_S[INDEX2(5,3,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 + 2*tmp10 + tmp7;
+                                EM_S[INDEX2(6,3,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp4 + tmp3 + tmp9;
                                 EM_S[INDEX2(7,3,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + 2*tmp9 + tmp0;
+                                EM_S[INDEX2(0,4,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + 2*tmp9 + tmp0;
+                                EM_S[INDEX2(1,4,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp4 + tmp3 + tmp9;
+                                EM_S[INDEX2(2,4,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 + 2*tmp10 + tmp7;
+                                EM_S[INDEX2(3,4,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp2 + tmp4 + tmp10;
+                                EM_S[INDEX2(4,4,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp6 + 2*tmp8;
+                                EM_S[INDEX2(5,4,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp8 + 2*tmp3 + 2*tmp5;
+                                EM_S[INDEX2(6,4,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + tmp6 + 2*tmp11 + 2*tmp1;
                                 EM_S[INDEX2(7,4,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + tmp11 + 2*tmp2;
+                                EM_S[INDEX2(0,5,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp6 + tmp1 + tmp9;
+                                EM_S[INDEX2(1,5,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp9 + tmp2 + 2*tmp5;
+                                EM_S[INDEX2(2,5,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp10 + tmp0 + tmp6;
+                                EM_S[INDEX2(3,5,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp3 + 2*tmp10;
+                                EM_S[INDEX2(4,5,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + tmp8 + 2*tmp1;
+                                EM_S[INDEX2(5,5,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp8 + 2*tmp4 + 2*tmp2;
+                                EM_S[INDEX2(6,5,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 + tmp11 + tmp7;
                                 EM_S[INDEX2(7,5,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp3 + tmp4 + 2*tmp11;
+                                EM_S[INDEX2(0,6,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp8 + tmp3 + tmp7;
+                                EM_S[INDEX2(1,6,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp4 + tmp0;
+                                EM_S[INDEX2(2,6,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp7 + tmp2 + 2*tmp11;
+                                EM_S[INDEX2(3,6,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + tmp1 + 2*tmp4;
+                                EM_S[INDEX2(4,6,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + 2*tmp3 + tmp6;
+                                EM_S[INDEX2(5,6,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp5 + 2*tmp0 + tmp9;
+                                EM_S[INDEX2(6,6,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp6 + 2*tmp10 + 2*tmp2;
                                 EM_S[INDEX2(7,6,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp10 + 2*tmp1 + 2*tmp5;
+                                EM_S[INDEX2(0,7,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp8 + tmp2 + tmp6;
+                                EM_S[INDEX2(1,7,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp5 + tmp1 + 2*tmp8;
+                                EM_S[INDEX2(2,7,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + tmp11 + 2*tmp6 + tmp3;
+                                EM_S[INDEX2(3,7,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 + 2*tmp11 + 2*tmp5;
+                                EM_S[INDEX2(4,7,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp7 + tmp9 + 2*tmp2;
+                                EM_S[INDEX2(5,7,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp9 + tmp4 + 2*tmp1;
+                                EM_S[INDEX2(6,7,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + 2*tmp7 + 2*tmp3 + tmp10;
                                 EM_S[INDEX2(7,7,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp4 + 2*tmp10;
                             }
                         }
@@ -964,7 +979,6 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                         // process B //
                         ///////////////
                         if (!B.isEmpty()) {
-                            add_EM_S=true;
                             const double* B_p=B.getSampleDataRO(e);
                             if (B.actsExpanded()) {
                                 const double B_0_0 = B_p[INDEX2(0,0,3)];
@@ -1256,136 +1270,136 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                                 const double tmp262 = w32*(-B_2_1 - B_2_3);
                                 const double tmp263 = w43*(-B_2_4 - B_2_6);
                                 EM_S[INDEX2(0,0,8)]+=-B_0_0*w47 - B_0_1*w38 - B_0_6*w30 - B_0_7*w46 + B_1_0*w44 - B_1_2*w39 - B_1_5*w31 + B_1_7*w45 - B_2_0*w40 - B_2_3*w32 - B_2_4*w43 - B_2_7*w41 + tmp132 + tmp133 + tmp208 + tmp209 + tmp210 + tmp211;
-                                EM_S[INDEX2(0,1,8)]+=-B_0_0*w38 - B_0_1*w47 - B_0_6*w46 - B_0_7*w30 + tmp128 + tmp129 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                EM_S[INDEX2(0,2,8)]+=-B_1_0*w39 + B_1_2*w44 + B_1_5*w45 - B_1_7*w31 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp173 + tmp179;
-                                EM_S[INDEX2(0,3,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp42 + tmp43 + tmp96 + tmp97 + tmp98 + tmp99;
-                                EM_S[INDEX2(0,4,8)]+=-B_2_0*w43 - B_2_3*w41 - B_2_4*w40 - B_2_7*w32 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
-                                EM_S[INDEX2(0,5,8)]+=tmp190 + tmp193 + tmp195 + tmp196 + tmp197 + tmp199 + tmp224 + tmp225 + tmp226 + tmp227;
-                                EM_S[INDEX2(0,6,8)]+=tmp234 + tmp235 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
-                                EM_S[INDEX2(0,7,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
                                 EM_S[INDEX2(1,0,8)]+=B_0_0*w47 + B_0_1*w38 + B_0_6*w30 + B_0_7*w46 + tmp148 + tmp149 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                EM_S[INDEX2(1,1,8)]+=B_0_0*w38 + B_0_1*w47 + B_0_6*w46 + B_0_7*w30 + B_1_1*w44 - B_1_3*w39 - B_1_4*w31 + B_1_6*w45 - B_2_1*w40 - B_2_2*w32 - B_2_5*w43 - B_2_6*w41 + tmp152 + tmp155 + tmp164 + tmp165 + tmp168 + tmp169;
-                                EM_S[INDEX2(1,2,8)]+=tmp103 + tmp40 + tmp42 + tmp43 + tmp46 + tmp47 + tmp48 + tmp97 + tmp98 + tmp99;
-                                EM_S[INDEX2(1,3,8)]+=-B_1_1*w39 + B_1_3*w44 + B_1_4*w45 - B_1_6*w31 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
-                                EM_S[INDEX2(1,4,8)]+=tmp193 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
-                                EM_S[INDEX2(1,5,8)]+=-B_2_1*w43 - B_2_2*w41 - B_2_5*w40 - B_2_6*w32 + tmp72 + tmp73 + tmp82 + tmp83 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
-                                EM_S[INDEX2(1,6,8)]+=tmp60 + tmp61 + tmp62 + tmp65 + tmp80 + tmp81;
-                                EM_S[INDEX2(1,7,8)]+=tmp180 + tmp183 + tmp185 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
                                 EM_S[INDEX2(2,0,8)]+=-B_1_0*w44 + B_1_2*w39 + B_1_5*w31 - B_1_7*w45 + tmp138 + tmp139 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147;
-                                EM_S[INDEX2(2,1,8)]+=tmp100 + tmp101 + tmp102 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp49 + tmp96;
-                                EM_S[INDEX2(2,2,8)]+=-B_0_2*w47 - B_0_3*w38 - B_0_4*w30 - B_0_5*w46 + B_1_0*w39 - B_1_2*w44 - B_1_5*w45 + B_1_7*w31 - B_2_1*w32 - B_2_2*w40 - B_2_5*w41 - B_2_6*w43 + tmp153 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
-                                EM_S[INDEX2(2,3,8)]+=-B_0_2*w38 - B_0_3*w47 - B_0_4*w46 - B_0_5*w30 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
-                                EM_S[INDEX2(2,4,8)]+=tmp228 + tmp231 + tmp233 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
-                                EM_S[INDEX2(2,5,8)]+=tmp60 + tmp61 + tmp63 + tmp64 + tmp94 + tmp95;
-                                EM_S[INDEX2(2,6,8)]+=-B_2_1*w41 - B_2_2*w43 - B_2_5*w32 - B_2_6*w40 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
-                                EM_S[INDEX2(2,7,8)]+=tmp107 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
                                 EM_S[INDEX2(3,0,8)]+=tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49;
-                                EM_S[INDEX2(3,1,8)]+=-B_1_1*w44 + B_1_3*w39 + B_1_4*w31 - B_1_6*w45 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp33 + tmp39;
-                                EM_S[INDEX2(3,2,8)]+=B_0_2*w47 + B_0_3*w38 + B_0_4*w30 + B_0_5*w46 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp56 + tmp57;
-                                EM_S[INDEX2(3,3,8)]+=B_0_2*w38 + B_0_3*w47 + B_0_4*w46 + B_0_5*w30 + B_1_1*w39 - B_1_3*w44 - B_1_4*w45 + B_1_6*w31 - B_2_0*w32 - B_2_3*w40 - B_2_4*w41 - B_2_7*w43 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
-                                EM_S[INDEX2(3,4,8)]+=tmp60 + tmp61 + tmp80 + tmp81 + tmp94 + tmp95;
-                                EM_S[INDEX2(3,5,8)]+=tmp186 + tmp187 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
-                                EM_S[INDEX2(3,6,8)]+=tmp104 + tmp107 + tmp109 + tmp110 + tmp111 + tmp113 + tmp160 + tmp161 + tmp162 + tmp163;
-                                EM_S[INDEX2(3,7,8)]+=-B_2_0*w41 - B_2_3*w43 - B_2_4*w32 - B_2_7*w40 + tmp0 + tmp1 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
                                 EM_S[INDEX2(4,0,8)]+=B_2_0*w40 + B_2_3*w32 + B_2_4*w43 + B_2_7*w41 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp2 + tmp3;
-                                EM_S[INDEX2(4,1,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
-                                EM_S[INDEX2(4,2,8)]+=tmp229 + tmp230 + tmp232 + tmp234 + tmp235 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
-                                EM_S[INDEX2(4,3,8)]+=tmp258 + tmp259 + tmp62 + tmp63 + tmp64 + tmp65;
-                                EM_S[INDEX2(4,4,8)]+=-B_0_2*w30 - B_0_3*w46 - B_0_4*w47 - B_0_5*w38 - B_1_1*w31 + B_1_3*w45 + B_1_4*w44 - B_1_6*w39 + B_2_0*w43 + B_2_3*w41 + B_2_4*w40 + B_2_7*w32 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
-                                EM_S[INDEX2(4,5,8)]+=-B_0_2*w46 - B_0_3*w30 - B_0_4*w38 - B_0_5*w47 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp58 + tmp59;
-                                EM_S[INDEX2(4,6,8)]+=B_1_1*w45 - B_1_3*w31 - B_1_4*w39 + B_1_6*w44 + tmp23 + tmp29 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38;
-                                EM_S[INDEX2(4,7,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
                                 EM_S[INDEX2(5,0,8)]+=tmp191 + tmp192 + tmp193 + tmp194 + tmp198 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217;
-                                EM_S[INDEX2(5,1,8)]+=B_2_1*w40 + B_2_2*w32 + B_2_5*w43 + B_2_6*w41 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
-                                EM_S[INDEX2(5,2,8)]+=tmp258 + tmp259 + tmp62 + tmp65 + tmp80 + tmp81;
-                                EM_S[INDEX2(5,3,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
-                                EM_S[INDEX2(5,4,8)]+=B_0_2*w30 + B_0_3*w46 + B_0_4*w47 + B_0_5*w38 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
-                                EM_S[INDEX2(5,5,8)]+=B_0_2*w46 + B_0_3*w30 + B_0_4*w38 + B_0_5*w47 - B_1_0*w31 + B_1_2*w45 + B_1_5*w44 - B_1_7*w39 + B_2_1*w43 + B_2_2*w41 + B_2_5*w40 + B_2_6*w32 + tmp135 + tmp136 + tmp208 + tmp211 + tmp212 + tmp213;
-                                EM_S[INDEX2(5,6,8)]+=tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
-                                EM_S[INDEX2(5,7,8)]+=B_1_0*w45 - B_1_2*w31 - B_1_5*w39 + B_1_7*w44 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
                                 EM_S[INDEX2(6,0,8)]+=tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233 + tmp234 + tmp235 + tmp236 + tmp237;
-                                EM_S[INDEX2(6,1,8)]+=tmp258 + tmp259 + tmp63 + tmp64 + tmp94 + tmp95;
-                                EM_S[INDEX2(6,2,8)]+=B_2_1*w32 + B_2_2*w40 + B_2_5*w41 + B_2_6*w43 + tmp70 + tmp71 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp84 + tmp85;
-                                EM_S[INDEX2(6,3,8)]+=tmp105 + tmp106 + tmp107 + tmp108 + tmp112 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
-                                EM_S[INDEX2(6,4,8)]+=B_1_1*w31 - B_1_3*w45 - B_1_4*w44 + B_1_6*w39 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
-                                EM_S[INDEX2(6,5,8)]+=tmp10 + tmp12 + tmp13 + tmp16 + tmp17 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
-                                EM_S[INDEX2(6,6,8)]+=-B_0_0*w30 - B_0_1*w46 - B_0_6*w47 - B_0_7*w38 - B_1_1*w45 + B_1_3*w31 + B_1_4*w39 - B_1_6*w44 + B_2_1*w41 + B_2_2*w43 + B_2_5*w32 + B_2_6*w40 + tmp134 + tmp137 + tmp209 + tmp210 + tmp212 + tmp213;
-                                EM_S[INDEX2(6,7,8)]+=-B_0_0*w46 - B_0_1*w30 - B_0_6*w38 - B_0_7*w47 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
                                 EM_S[INDEX2(7,0,8)]+=tmp258 + tmp259 + tmp80 + tmp81 + tmp94 + tmp95;
+                                EM_S[INDEX2(0,1,8)]+=-B_0_0*w38 - B_0_1*w47 - B_0_6*w46 - B_0_7*w30 + tmp128 + tmp129 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
+                                EM_S[INDEX2(1,1,8)]+=B_0_0*w38 + B_0_1*w47 + B_0_6*w46 + B_0_7*w30 + B_1_1*w44 - B_1_3*w39 - B_1_4*w31 + B_1_6*w45 - B_2_1*w40 - B_2_2*w32 - B_2_5*w43 - B_2_6*w41 + tmp152 + tmp155 + tmp164 + tmp165 + tmp168 + tmp169;
+                                EM_S[INDEX2(2,1,8)]+=tmp100 + tmp101 + tmp102 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp49 + tmp96;
+                                EM_S[INDEX2(3,1,8)]+=-B_1_1*w44 + B_1_3*w39 + B_1_4*w31 - B_1_6*w45 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp33 + tmp39;
+                                EM_S[INDEX2(4,1,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
+                                EM_S[INDEX2(5,1,8)]+=B_2_1*w40 + B_2_2*w32 + B_2_5*w43 + B_2_6*w41 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
+                                EM_S[INDEX2(6,1,8)]+=tmp258 + tmp259 + tmp63 + tmp64 + tmp94 + tmp95;
                                 EM_S[INDEX2(7,1,8)]+=tmp181 + tmp182 + tmp184 + tmp186 + tmp187 + tmp188 + tmp218 + tmp219 + tmp220 + tmp221;
+                                EM_S[INDEX2(0,2,8)]+=-B_1_0*w39 + B_1_2*w44 + B_1_5*w45 - B_1_7*w31 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp173 + tmp179;
+                                EM_S[INDEX2(1,2,8)]+=tmp103 + tmp40 + tmp42 + tmp43 + tmp46 + tmp47 + tmp48 + tmp97 + tmp98 + tmp99;
+                                EM_S[INDEX2(2,2,8)]+=-B_0_2*w47 - B_0_3*w38 - B_0_4*w30 - B_0_5*w46 + B_1_0*w39 - B_1_2*w44 - B_1_5*w45 + B_1_7*w31 - B_2_1*w32 - B_2_2*w40 - B_2_5*w41 - B_2_6*w43 + tmp153 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
+                                EM_S[INDEX2(3,2,8)]+=B_0_2*w47 + B_0_3*w38 + B_0_4*w30 + B_0_5*w46 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp56 + tmp57;
+                                EM_S[INDEX2(4,2,8)]+=tmp229 + tmp230 + tmp232 + tmp234 + tmp235 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
+                                EM_S[INDEX2(5,2,8)]+=tmp258 + tmp259 + tmp62 + tmp65 + tmp80 + tmp81;
+                                EM_S[INDEX2(6,2,8)]+=B_2_1*w32 + B_2_2*w40 + B_2_5*w41 + B_2_6*w43 + tmp70 + tmp71 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp84 + tmp85;
                                 EM_S[INDEX2(7,2,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113;
+                                EM_S[INDEX2(0,3,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp42 + tmp43 + tmp96 + tmp97 + tmp98 + tmp99;
+                                EM_S[INDEX2(1,3,8)]+=-B_1_1*w39 + B_1_3*w44 + B_1_4*w45 - B_1_6*w31 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
+                                EM_S[INDEX2(2,3,8)]+=-B_0_2*w38 - B_0_3*w47 - B_0_4*w46 - B_0_5*w30 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
+                                EM_S[INDEX2(3,3,8)]+=B_0_2*w38 + B_0_3*w47 + B_0_4*w46 + B_0_5*w30 + B_1_1*w39 - B_1_3*w44 - B_1_4*w45 + B_1_6*w31 - B_2_0*w32 - B_2_3*w40 - B_2_4*w41 - B_2_7*w43 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
+                                EM_S[INDEX2(4,3,8)]+=tmp258 + tmp259 + tmp62 + tmp63 + tmp64 + tmp65;
+                                EM_S[INDEX2(5,3,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
+                                EM_S[INDEX2(6,3,8)]+=tmp105 + tmp106 + tmp107 + tmp108 + tmp112 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
                                 EM_S[INDEX2(7,3,8)]+=B_2_0*w32 + B_2_3*w40 + B_2_4*w41 + B_2_7*w43 + tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
+                                EM_S[INDEX2(0,4,8)]+=-B_2_0*w43 - B_2_3*w41 - B_2_4*w40 - B_2_7*w32 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
+                                EM_S[INDEX2(1,4,8)]+=tmp193 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
+                                EM_S[INDEX2(2,4,8)]+=tmp228 + tmp231 + tmp233 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
+                                EM_S[INDEX2(3,4,8)]+=tmp60 + tmp61 + tmp80 + tmp81 + tmp94 + tmp95;
+                                EM_S[INDEX2(4,4,8)]+=-B_0_2*w30 - B_0_3*w46 - B_0_4*w47 - B_0_5*w38 - B_1_1*w31 + B_1_3*w45 + B_1_4*w44 - B_1_6*w39 + B_2_0*w43 + B_2_3*w41 + B_2_4*w40 + B_2_7*w32 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
+                                EM_S[INDEX2(5,4,8)]+=B_0_2*w30 + B_0_3*w46 + B_0_4*w47 + B_0_5*w38 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
+                                EM_S[INDEX2(6,4,8)]+=B_1_1*w31 - B_1_3*w45 - B_1_4*w44 + B_1_6*w39 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
                                 EM_S[INDEX2(7,4,8)]+=tmp12 + tmp13 + tmp250 + tmp251 + tmp252 + tmp253 + tmp66 + tmp67 + tmp68 + tmp69;
+                                EM_S[INDEX2(0,5,8)]+=tmp190 + tmp193 + tmp195 + tmp196 + tmp197 + tmp199 + tmp224 + tmp225 + tmp226 + tmp227;
+                                EM_S[INDEX2(1,5,8)]+=-B_2_1*w43 - B_2_2*w41 - B_2_5*w40 - B_2_6*w32 + tmp72 + tmp73 + tmp82 + tmp83 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
+                                EM_S[INDEX2(2,5,8)]+=tmp60 + tmp61 + tmp63 + tmp64 + tmp94 + tmp95;
+                                EM_S[INDEX2(3,5,8)]+=tmp186 + tmp187 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
+                                EM_S[INDEX2(4,5,8)]+=-B_0_2*w46 - B_0_3*w30 - B_0_4*w38 - B_0_5*w47 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp58 + tmp59;
+                                EM_S[INDEX2(5,5,8)]+=B_0_2*w46 + B_0_3*w30 + B_0_4*w38 + B_0_5*w47 - B_1_0*w31 + B_1_2*w45 + B_1_5*w44 - B_1_7*w39 + B_2_1*w43 + B_2_2*w41 + B_2_5*w40 + B_2_6*w32 + tmp135 + tmp136 + tmp208 + tmp211 + tmp212 + tmp213;
+                                EM_S[INDEX2(6,5,8)]+=tmp10 + tmp12 + tmp13 + tmp16 + tmp17 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
                                 EM_S[INDEX2(7,5,8)]+=B_1_0*w31 - B_1_2*w45 - B_1_5*w44 + B_1_7*w39 + tmp141 + tmp147 + tmp170 + tmp171 + tmp172 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178;
+                                EM_S[INDEX2(0,6,8)]+=tmp234 + tmp235 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
+                                EM_S[INDEX2(1,6,8)]+=tmp60 + tmp61 + tmp62 + tmp65 + tmp80 + tmp81;
+                                EM_S[INDEX2(2,6,8)]+=-B_2_1*w41 - B_2_2*w43 - B_2_5*w32 - B_2_6*w40 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
+                                EM_S[INDEX2(3,6,8)]+=tmp104 + tmp107 + tmp109 + tmp110 + tmp111 + tmp113 + tmp160 + tmp161 + tmp162 + tmp163;
+                                EM_S[INDEX2(4,6,8)]+=B_1_1*w45 - B_1_3*w31 - B_1_4*w39 + B_1_6*w44 + tmp23 + tmp29 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38;
+                                EM_S[INDEX2(5,6,8)]+=tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
+                                EM_S[INDEX2(6,6,8)]+=-B_0_0*w30 - B_0_1*w46 - B_0_6*w47 - B_0_7*w38 - B_1_1*w45 + B_1_3*w31 + B_1_4*w39 - B_1_6*w44 + B_2_1*w41 + B_2_2*w43 + B_2_5*w32 + B_2_6*w40 + tmp134 + tmp137 + tmp209 + tmp210 + tmp212 + tmp213;
                                 EM_S[INDEX2(7,6,8)]+=B_0_0*w30 + B_0_1*w46 + B_0_6*w47 + B_0_7*w38 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp130 + tmp131 + tmp148 + tmp149;
+                                EM_S[INDEX2(0,7,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
+                                EM_S[INDEX2(1,7,8)]+=tmp180 + tmp183 + tmp185 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
+                                EM_S[INDEX2(2,7,8)]+=tmp107 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
+                                EM_S[INDEX2(3,7,8)]+=-B_2_0*w41 - B_2_3*w43 - B_2_4*w32 - B_2_7*w40 + tmp0 + tmp1 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
+                                EM_S[INDEX2(4,7,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
+                                EM_S[INDEX2(5,7,8)]+=B_1_0*w45 - B_1_2*w31 - B_1_5*w39 + B_1_7*w44 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
+                                EM_S[INDEX2(6,7,8)]+=-B_0_0*w46 - B_0_1*w30 - B_0_6*w38 - B_0_7*w47 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
                                 EM_S[INDEX2(7,7,8)]+=B_0_0*w46 + B_0_1*w30 + B_0_6*w38 + B_0_7*w47 - B_1_0*w45 + B_1_2*w31 + B_1_5*w39 - B_1_7*w44 + B_2_0*w41 + B_2_3*w43 + B_2_4*w32 + B_2_7*w40 + tmp150 + tmp151 + tmp166 + tmp167 + tmp168 + tmp169;
                             } else { // constant data
                                 const double wB0 = B_p[0]*w53;
                                 const double wB1 = B_p[1]*w51;
                                 const double wB2 = B_p[2]*w50;
                                 EM_S[INDEX2(0,0,8)]+= 4*wB0 + 4*wB1 - 4*wB2;
-                                EM_S[INDEX2(0,1,8)]+= 4*wB0 + 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(0,2,8)]+= 2*wB0 + 4*wB1 - 2*wB2;
-                                EM_S[INDEX2(0,3,8)]+= 2*wB0 + 2*wB1 - wB2;
-                                EM_S[INDEX2(0,4,8)]+= 2*wB0 + 2*wB1 - 4*wB2;
-                                EM_S[INDEX2(0,5,8)]+= 2*wB0 +   wB1 - 2*wB2;
-                                EM_S[INDEX2(0,6,8)]+=   wB0 + 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(0,7,8)]+=   wB0 +   wB1 - wB2;
                                 EM_S[INDEX2(1,0,8)]+=-4*wB0 + 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(1,1,8)]+=-4*wB0 + 4*wB1 - 4*wB2;
-                                EM_S[INDEX2(1,2,8)]+=-2*wB0 + 2*wB1 - wB2;
-                                EM_S[INDEX2(1,3,8)]+=-2*wB0 + 4*wB1 - 2*wB2;
-                                EM_S[INDEX2(1,4,8)]+=-2*wB0 +   wB1 - 2*wB2;
-                                EM_S[INDEX2(1,5,8)]+=-2*wB0 + 2*wB1 - 4*wB2;
-                                EM_S[INDEX2(1,6,8)]+=  -wB0 +   wB1 - wB2;
-                                EM_S[INDEX2(1,7,8)]+=  -wB0 + 2*wB1 - 2*wB2;
                                 EM_S[INDEX2(2,0,8)]+= 2*wB0 - 4*wB1 - 2*wB2;
-                                EM_S[INDEX2(2,1,8)]+= 2*wB0 - 2*wB1 - wB2;
-                                EM_S[INDEX2(2,2,8)]+= 4*wB0 - 4*wB1 - 4*wB2;
-                                EM_S[INDEX2(2,3,8)]+= 4*wB0 - 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(2,4,8)]+=   wB0 - 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(2,5,8)]+=   wB0 -   wB1 - wB2;
-                                EM_S[INDEX2(2,6,8)]+= 2*wB0 - 2*wB1 - 4*wB2;
-                                EM_S[INDEX2(2,7,8)]+= 2*wB0 -   wB1 - 2*wB2;
                                 EM_S[INDEX2(3,0,8)]+=-2*wB0 - 2*wB1 - wB2;
-                                EM_S[INDEX2(3,1,8)]+=-2*wB0 - 4*wB1 - 2*wB2;
-                                EM_S[INDEX2(3,2,8)]+=-4*wB0 - 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(3,3,8)]+=-4*wB0 - 4*wB1 - 4*wB2;
-                                EM_S[INDEX2(3,4,8)]+=  -wB0 -   wB1 - wB2;
-                                EM_S[INDEX2(3,5,8)]+=  -wB0 - 2*wB1 - 2*wB2;
-                                EM_S[INDEX2(3,6,8)]+=-2*wB0 -   wB1 - 2*wB2;
-                                EM_S[INDEX2(3,7,8)]+=-2*wB0 - 2*wB1 - 4*wB2;
                                 EM_S[INDEX2(4,0,8)]+= 2*wB0 + 2*wB1 + 4*wB2;
-                                EM_S[INDEX2(4,1,8)]+= 2*wB0 +   wB1 + 2*wB2;
-                                EM_S[INDEX2(4,2,8)]+=   wB0 + 2*wB1 + 2*wB2;
-                                EM_S[INDEX2(4,3,8)]+=   wB0 +   wB1 + wB2;
-                                EM_S[INDEX2(4,4,8)]+= 4*wB0 + 4*wB1 + 4*wB2;
-                                EM_S[INDEX2(4,5,8)]+= 4*wB0 + 2*wB1 + 2*wB2;
-                                EM_S[INDEX2(4,6,8)]+= 2*wB0 + 4*wB1 + 2*wB2;
-                                EM_S[INDEX2(4,7,8)]+= 2*wB0 + 2*wB1 + wB2;
                                 EM_S[INDEX2(5,0,8)]+=-2*wB0 +   wB1 + 2*wB2;
-                                EM_S[INDEX2(5,1,8)]+=-2*wB0 + 2*wB1 + 4*wB2;
-                                EM_S[INDEX2(5,2,8)]+=  -wB0 +   wB1 + wB2;
-                                EM_S[INDEX2(5,3,8)]+=  -wB0 + 2*wB1 + 2*wB2;
-                                EM_S[INDEX2(5,4,8)]+=-4*wB0 + 2*wB1 + 2*wB2;
-                                EM_S[INDEX2(5,5,8)]+=-4*wB0 + 4*wB1 + 4*wB2;
-                                EM_S[INDEX2(5,6,8)]+=-2*wB0 + 2*wB1 + wB2;
-                                EM_S[INDEX2(5,7,8)]+=-2*wB0 + 4*wB1 + 2*wB2;
                                 EM_S[INDEX2(6,0,8)]+=   wB0 - 2*wB1 + 2*wB2;
-                                EM_S[INDEX2(6,1,8)]+=   wB0 -   wB1 + wB2;
-                                EM_S[INDEX2(6,2,8)]+= 2*wB0 - 2*wB1 + 4*wB2;
-                                EM_S[INDEX2(6,3,8)]+= 2*wB0 -   wB1 + 2*wB2;
-                                EM_S[INDEX2(6,4,8)]+= 2*wB0 - 4*wB1 + 2*wB2;
-                                EM_S[INDEX2(6,5,8)]+= 2*wB0 - 2*wB1 + wB2;
-                                EM_S[INDEX2(6,6,8)]+= 4*wB0 - 4*wB1 + 4*wB2;
-                                EM_S[INDEX2(6,7,8)]+= 4*wB0 - 2*wB1 + 2*wB2;
                                 EM_S[INDEX2(7,0,8)]+=  -wB0 -   wB1 + wB2;
+                                EM_S[INDEX2(0,1,8)]+= 4*wB0 + 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(1,1,8)]+=-4*wB0 + 4*wB1 - 4*wB2;
+                                EM_S[INDEX2(2,1,8)]+= 2*wB0 - 2*wB1 - wB2;
+                                EM_S[INDEX2(3,1,8)]+=-2*wB0 - 4*wB1 - 2*wB2;
+                                EM_S[INDEX2(4,1,8)]+= 2*wB0 +   wB1 + 2*wB2;
+                                EM_S[INDEX2(5,1,8)]+=-2*wB0 + 2*wB1 + 4*wB2;
+                                EM_S[INDEX2(6,1,8)]+=   wB0 -   wB1 + wB2;
                                 EM_S[INDEX2(7,1,8)]+=  -wB0 - 2*wB1 + 2*wB2;
+                                EM_S[INDEX2(0,2,8)]+= 2*wB0 + 4*wB1 - 2*wB2;
+                                EM_S[INDEX2(1,2,8)]+=-2*wB0 + 2*wB1 - wB2;
+                                EM_S[INDEX2(2,2,8)]+= 4*wB0 - 4*wB1 - 4*wB2;
+                                EM_S[INDEX2(3,2,8)]+=-4*wB0 - 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(4,2,8)]+=   wB0 + 2*wB1 + 2*wB2;
+                                EM_S[INDEX2(5,2,8)]+=  -wB0 +   wB1 + wB2;
+                                EM_S[INDEX2(6,2,8)]+= 2*wB0 - 2*wB1 + 4*wB2;
                                 EM_S[INDEX2(7,2,8)]+=-2*wB0 -   wB1 + 2*wB2;
+                                EM_S[INDEX2(0,3,8)]+= 2*wB0 + 2*wB1 - wB2;
+                                EM_S[INDEX2(1,3,8)]+=-2*wB0 + 4*wB1 - 2*wB2;
+                                EM_S[INDEX2(2,3,8)]+= 4*wB0 - 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(3,3,8)]+=-4*wB0 - 4*wB1 - 4*wB2;
+                                EM_S[INDEX2(4,3,8)]+=   wB0 +   wB1 + wB2;
+                                EM_S[INDEX2(5,3,8)]+=  -wB0 + 2*wB1 + 2*wB2;
+                                EM_S[INDEX2(6,3,8)]+= 2*wB0 -   wB1 + 2*wB2;
                                 EM_S[INDEX2(7,3,8)]+=-2*wB0 - 2*wB1 + 4*wB2;
+                                EM_S[INDEX2(0,4,8)]+= 2*wB0 + 2*wB1 - 4*wB2;
+                                EM_S[INDEX2(1,4,8)]+=-2*wB0 +   wB1 - 2*wB2;
+                                EM_S[INDEX2(2,4,8)]+=   wB0 - 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(3,4,8)]+=  -wB0 -   wB1 - wB2;
+                                EM_S[INDEX2(4,4,8)]+= 4*wB0 + 4*wB1 + 4*wB2;
+                                EM_S[INDEX2(5,4,8)]+=-4*wB0 + 2*wB1 + 2*wB2;
+                                EM_S[INDEX2(6,4,8)]+= 2*wB0 - 4*wB1 + 2*wB2;
                                 EM_S[INDEX2(7,4,8)]+=-2*wB0 - 2*wB1 + wB2;
+                                EM_S[INDEX2(0,5,8)]+= 2*wB0 +   wB1 - 2*wB2;
+                                EM_S[INDEX2(1,5,8)]+=-2*wB0 + 2*wB1 - 4*wB2;
+                                EM_S[INDEX2(2,5,8)]+=   wB0 -   wB1 - wB2;
+                                EM_S[INDEX2(3,5,8)]+=  -wB0 - 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(4,5,8)]+= 4*wB0 + 2*wB1 + 2*wB2;
+                                EM_S[INDEX2(5,5,8)]+=-4*wB0 + 4*wB1 + 4*wB2;
+                                EM_S[INDEX2(6,5,8)]+= 2*wB0 - 2*wB1 + wB2;
                                 EM_S[INDEX2(7,5,8)]+=-2*wB0 - 4*wB1 + 2*wB2;
+                                EM_S[INDEX2(0,6,8)]+=   wB0 + 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(1,6,8)]+=  -wB0 +   wB1 - wB2;
+                                EM_S[INDEX2(2,6,8)]+= 2*wB0 - 2*wB1 - 4*wB2;
+                                EM_S[INDEX2(3,6,8)]+=-2*wB0 -   wB1 - 2*wB2;
+                                EM_S[INDEX2(4,6,8)]+= 2*wB0 + 4*wB1 + 2*wB2;
+                                EM_S[INDEX2(5,6,8)]+=-2*wB0 + 2*wB1 + wB2;
+                                EM_S[INDEX2(6,6,8)]+= 4*wB0 - 4*wB1 + 4*wB2;
                                 EM_S[INDEX2(7,6,8)]+=-4*wB0 - 2*wB1 + 2*wB2;
+                                EM_S[INDEX2(0,7,8)]+=   wB0 +   wB1 - wB2;
+                                EM_S[INDEX2(1,7,8)]+=  -wB0 + 2*wB1 - 2*wB2;
+                                EM_S[INDEX2(2,7,8)]+= 2*wB0 -   wB1 - 2*wB2;
+                                EM_S[INDEX2(3,7,8)]+=-2*wB0 - 2*wB1 - 4*wB2;
+                                EM_S[INDEX2(4,7,8)]+= 2*wB0 + 2*wB1 + wB2;
+                                EM_S[INDEX2(5,7,8)]+=-2*wB0 + 4*wB1 + 2*wB2;
+                                EM_S[INDEX2(6,7,8)]+= 4*wB0 - 2*wB1 + 2*wB2;
                                 EM_S[INDEX2(7,7,8)]+=-4*wB0 - 4*wB1 + 4*wB2;
                             }
                         }
@@ -1393,7 +1407,6 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                         // process C //
                         ///////////////
                         if (!C.isEmpty()) {
-                            add_EM_S=true;
                             const double* C_p=C.getSampleDataRO(e);
                             if (C.actsExpanded()) {
                                 const double C_0_0 = C_p[INDEX2(0,0,3)];
@@ -1685,136 +1698,136 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                                 const double tmp262 = w32*(C_2_5 + C_2_7);
                                 const double tmp263 = w43*(C_2_0 + C_2_2);
                                 EM_S[INDEX2(0,0,8)]+=-C_0_0*w47 - C_0_1*w38 - C_0_6*w30 - C_0_7*w46 + C_1_0*w44 - C_1_2*w39 - C_1_5*w31 + C_1_7*w45 - C_2_0*w40 - C_2_3*w32 - C_2_4*w43 - C_2_7*w41 + tmp132 + tmp133 + tmp208 + tmp209 + tmp210 + tmp211;
-                                EM_S[INDEX2(0,1,8)]+=C_0_0*w47 + C_0_1*w38 + C_0_6*w30 + C_0_7*w46 + tmp128 + tmp129 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                EM_S[INDEX2(0,2,8)]+=-C_1_0*w44 + C_1_2*w39 + C_1_5*w31 - C_1_7*w45 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp173 + tmp179;
-                                EM_S[INDEX2(0,3,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp42 + tmp43 + tmp96 + tmp97 + tmp98 + tmp99;
-                                EM_S[INDEX2(0,4,8)]+=C_2_0*w40 + C_2_3*w32 + C_2_4*w43 + C_2_7*w41 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
-                                EM_S[INDEX2(0,5,8)]+=tmp190 + tmp193 + tmp195 + tmp196 + tmp197 + tmp199 + tmp224 + tmp225 + tmp226 + tmp227;
-                                EM_S[INDEX2(0,6,8)]+=tmp234 + tmp235 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
-                                EM_S[INDEX2(0,7,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
                                 EM_S[INDEX2(1,0,8)]+=-C_0_0*w38 - C_0_1*w47 - C_0_6*w46 - C_0_7*w30 + tmp148 + tmp149 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                EM_S[INDEX2(1,1,8)]+=C_0_0*w38 + C_0_1*w47 + C_0_6*w46 + C_0_7*w30 + C_1_1*w44 - C_1_3*w39 - C_1_4*w31 + C_1_6*w45 - C_2_1*w40 - C_2_2*w32 - C_2_5*w43 - C_2_6*w41 + tmp152 + tmp155 + tmp164 + tmp165 + tmp168 + tmp169;
-                                EM_S[INDEX2(1,2,8)]+=tmp103 + tmp40 + tmp42 + tmp43 + tmp46 + tmp47 + tmp48 + tmp97 + tmp98 + tmp99;
-                                EM_S[INDEX2(1,3,8)]+=-C_1_1*w44 + C_1_3*w39 + C_1_4*w31 - C_1_6*w45 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
-                                EM_S[INDEX2(1,4,8)]+=tmp193 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
-                                EM_S[INDEX2(1,5,8)]+=C_2_1*w40 + C_2_2*w32 + C_2_5*w43 + C_2_6*w41 + tmp72 + tmp73 + tmp82 + tmp83 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
-                                EM_S[INDEX2(1,6,8)]+=tmp60 + tmp61 + tmp62 + tmp65 + tmp80 + tmp81;
-                                EM_S[INDEX2(1,7,8)]+=tmp180 + tmp183 + tmp185 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
                                 EM_S[INDEX2(2,0,8)]+=-C_1_0*w39 + C_1_2*w44 + C_1_5*w45 - C_1_7*w31 + tmp138 + tmp139 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147;
-                                EM_S[INDEX2(2,1,8)]+=tmp100 + tmp101 + tmp102 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp49 + tmp96;
-                                EM_S[INDEX2(2,2,8)]+=-C_0_2*w47 - C_0_3*w38 - C_0_4*w30 - C_0_5*w46 + C_1_0*w39 - C_1_2*w44 - C_1_5*w45 + C_1_7*w31 - C_2_1*w32 - C_2_2*w40 - C_2_5*w41 - C_2_6*w43 + tmp153 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
-                                EM_S[INDEX2(2,3,8)]+=C_0_2*w47 + C_0_3*w38 + C_0_4*w30 + C_0_5*w46 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
-                                EM_S[INDEX2(2,4,8)]+=tmp228 + tmp231 + tmp233 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
-                                EM_S[INDEX2(2,5,8)]+=tmp60 + tmp61 + tmp63 + tmp64 + tmp94 + tmp95;
-                                EM_S[INDEX2(2,6,8)]+=C_2_1*w32 + C_2_2*w40 + C_2_5*w41 + C_2_6*w43 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
-                                EM_S[INDEX2(2,7,8)]+=tmp107 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
                                 EM_S[INDEX2(3,0,8)]+=tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49;
-                                EM_S[INDEX2(3,1,8)]+=-C_1_1*w39 + C_1_3*w44 + C_1_4*w45 - C_1_6*w31 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp33 + tmp39;
-                                EM_S[INDEX2(3,2,8)]+=-C_0_2*w38 - C_0_3*w47 - C_0_4*w46 - C_0_5*w30 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp56 + tmp57;
-                                EM_S[INDEX2(3,3,8)]+=C_0_2*w38 + C_0_3*w47 + C_0_4*w46 + C_0_5*w30 + C_1_1*w39 - C_1_3*w44 - C_1_4*w45 + C_1_6*w31 - C_2_0*w32 - C_2_3*w40 - C_2_4*w41 - C_2_7*w43 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
-                                EM_S[INDEX2(3,4,8)]+=tmp60 + tmp61 + tmp80 + tmp81 + tmp94 + tmp95;
-                                EM_S[INDEX2(3,5,8)]+=tmp186 + tmp187 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
-                                EM_S[INDEX2(3,6,8)]+=tmp104 + tmp107 + tmp109 + tmp110 + tmp111 + tmp113 + tmp160 + tmp161 + tmp162 + tmp163;
-                                EM_S[INDEX2(3,7,8)]+=C_2_0*w32 + C_2_3*w40 + C_2_4*w41 + C_2_7*w43 + tmp0 + tmp1 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
                                 EM_S[INDEX2(4,0,8)]+=-C_2_0*w43 - C_2_3*w41 - C_2_4*w40 - C_2_7*w32 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp2 + tmp3;
-                                EM_S[INDEX2(4,1,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
-                                EM_S[INDEX2(4,2,8)]+=tmp229 + tmp230 + tmp232 + tmp234 + tmp235 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
-                                EM_S[INDEX2(4,3,8)]+=tmp258 + tmp259 + tmp62 + tmp63 + tmp64 + tmp65;
-                                EM_S[INDEX2(4,4,8)]+=-C_0_2*w30 - C_0_3*w46 - C_0_4*w47 - C_0_5*w38 - C_1_1*w31 + C_1_3*w45 + C_1_4*w44 - C_1_6*w39 + C_2_0*w43 + C_2_3*w41 + C_2_4*w40 + C_2_7*w32 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
-                                EM_S[INDEX2(4,5,8)]+=C_0_2*w30 + C_0_3*w46 + C_0_4*w47 + C_0_5*w38 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp58 + tmp59;
-                                EM_S[INDEX2(4,6,8)]+=C_1_1*w31 - C_1_3*w45 - C_1_4*w44 + C_1_6*w39 + tmp23 + tmp29 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38;
-                                EM_S[INDEX2(4,7,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
                                 EM_S[INDEX2(5,0,8)]+=tmp191 + tmp192 + tmp193 + tmp194 + tmp198 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217;
-                                EM_S[INDEX2(5,1,8)]+=-C_2_1*w43 - C_2_2*w41 - C_2_5*w40 - C_2_6*w32 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
-                                EM_S[INDEX2(5,2,8)]+=tmp258 + tmp259 + tmp62 + tmp65 + tmp80 + tmp81;
-                                EM_S[INDEX2(5,3,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
-                                EM_S[INDEX2(5,4,8)]+=-C_0_2*w46 - C_0_3*w30 - C_0_4*w38 - C_0_5*w47 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
-                                EM_S[INDEX2(5,5,8)]+=C_0_2*w46 + C_0_3*w30 + C_0_4*w38 + C_0_5*w47 - C_1_0*w31 + C_1_2*w45 + C_1_5*w44 - C_1_7*w39 + C_2_1*w43 + C_2_2*w41 + C_2_5*w40 + C_2_6*w32 + tmp135 + tmp136 + tmp208 + tmp211 + tmp212 + tmp213;
-                                EM_S[INDEX2(5,6,8)]+=tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
-                                EM_S[INDEX2(5,7,8)]+=C_1_0*w31 - C_1_2*w45 - C_1_5*w44 + C_1_7*w39 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
                                 EM_S[INDEX2(6,0,8)]+=tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233 + tmp234 + tmp235 + tmp236 + tmp237;
-                                EM_S[INDEX2(6,1,8)]+=tmp258 + tmp259 + tmp63 + tmp64 + tmp94 + tmp95;
-                                EM_S[INDEX2(6,2,8)]+=-C_2_1*w41 - C_2_2*w43 - C_2_5*w32 - C_2_6*w40 + tmp70 + tmp71 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp84 + tmp85;
-                                EM_S[INDEX2(6,3,8)]+=tmp105 + tmp106 + tmp107 + tmp108 + tmp112 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
-                                EM_S[INDEX2(6,4,8)]+=C_1_1*w45 - C_1_3*w31 - C_1_4*w39 + C_1_6*w44 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
-                                EM_S[INDEX2(6,5,8)]+=tmp10 + tmp12 + tmp13 + tmp16 + tmp17 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
-                                EM_S[INDEX2(6,6,8)]+=-C_0_0*w30 - C_0_1*w46 - C_0_6*w47 - C_0_7*w38 - C_1_1*w45 + C_1_3*w31 + C_1_4*w39 - C_1_6*w44 + C_2_1*w41 + C_2_2*w43 + C_2_5*w32 + C_2_6*w40 + tmp134 + tmp137 + tmp209 + tmp210 + tmp212 + tmp213;
-                                EM_S[INDEX2(6,7,8)]+=C_0_0*w30 + C_0_1*w46 + C_0_6*w47 + C_0_7*w38 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
                                 EM_S[INDEX2(7,0,8)]+=tmp258 + tmp259 + tmp80 + tmp81 + tmp94 + tmp95;
+                                EM_S[INDEX2(0,1,8)]+=C_0_0*w47 + C_0_1*w38 + C_0_6*w30 + C_0_7*w46 + tmp128 + tmp129 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
+                                EM_S[INDEX2(1,1,8)]+=C_0_0*w38 + C_0_1*w47 + C_0_6*w46 + C_0_7*w30 + C_1_1*w44 - C_1_3*w39 - C_1_4*w31 + C_1_6*w45 - C_2_1*w40 - C_2_2*w32 - C_2_5*w43 - C_2_6*w41 + tmp152 + tmp155 + tmp164 + tmp165 + tmp168 + tmp169;
+                                EM_S[INDEX2(2,1,8)]+=tmp100 + tmp101 + tmp102 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp49 + tmp96;
+                                EM_S[INDEX2(3,1,8)]+=-C_1_1*w39 + C_1_3*w44 + C_1_4*w45 - C_1_6*w31 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp33 + tmp39;
+                                EM_S[INDEX2(4,1,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
+                                EM_S[INDEX2(5,1,8)]+=-C_2_1*w43 - C_2_2*w41 - C_2_5*w40 - C_2_6*w32 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
+                                EM_S[INDEX2(6,1,8)]+=tmp258 + tmp259 + tmp63 + tmp64 + tmp94 + tmp95;
                                 EM_S[INDEX2(7,1,8)]+=tmp181 + tmp182 + tmp184 + tmp186 + tmp187 + tmp188 + tmp218 + tmp219 + tmp220 + tmp221;
+                                EM_S[INDEX2(0,2,8)]+=-C_1_0*w44 + C_1_2*w39 + C_1_5*w31 - C_1_7*w45 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp173 + tmp179;
+                                EM_S[INDEX2(1,2,8)]+=tmp103 + tmp40 + tmp42 + tmp43 + tmp46 + tmp47 + tmp48 + tmp97 + tmp98 + tmp99;
+                                EM_S[INDEX2(2,2,8)]+=-C_0_2*w47 - C_0_3*w38 - C_0_4*w30 - C_0_5*w46 + C_1_0*w39 - C_1_2*w44 - C_1_5*w45 + C_1_7*w31 - C_2_1*w32 - C_2_2*w40 - C_2_5*w41 - C_2_6*w43 + tmp153 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
+                                EM_S[INDEX2(3,2,8)]+=-C_0_2*w38 - C_0_3*w47 - C_0_4*w46 - C_0_5*w30 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp56 + tmp57;
+                                EM_S[INDEX2(4,2,8)]+=tmp229 + tmp230 + tmp232 + tmp234 + tmp235 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
+                                EM_S[INDEX2(5,2,8)]+=tmp258 + tmp259 + tmp62 + tmp65 + tmp80 + tmp81;
+                                EM_S[INDEX2(6,2,8)]+=-C_2_1*w41 - C_2_2*w43 - C_2_5*w32 - C_2_6*w40 + tmp70 + tmp71 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp84 + tmp85;
                                 EM_S[INDEX2(7,2,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113;
+                                EM_S[INDEX2(0,3,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp42 + tmp43 + tmp96 + tmp97 + tmp98 + tmp99;
+                                EM_S[INDEX2(1,3,8)]+=-C_1_1*w44 + C_1_3*w39 + C_1_4*w31 - C_1_6*w45 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
+                                EM_S[INDEX2(2,3,8)]+=C_0_2*w47 + C_0_3*w38 + C_0_4*w30 + C_0_5*w46 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
+                                EM_S[INDEX2(3,3,8)]+=C_0_2*w38 + C_0_3*w47 + C_0_4*w46 + C_0_5*w30 + C_1_1*w39 - C_1_3*w44 - C_1_4*w45 + C_1_6*w31 - C_2_0*w32 - C_2_3*w40 - C_2_4*w41 - C_2_7*w43 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
+                                EM_S[INDEX2(4,3,8)]+=tmp258 + tmp259 + tmp62 + tmp63 + tmp64 + tmp65;
+                                EM_S[INDEX2(5,3,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
+                                EM_S[INDEX2(6,3,8)]+=tmp105 + tmp106 + tmp107 + tmp108 + tmp112 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
                                 EM_S[INDEX2(7,3,8)]+=-C_2_0*w41 - C_2_3*w43 - C_2_4*w32 - C_2_7*w40 + tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
+                                EM_S[INDEX2(0,4,8)]+=C_2_0*w40 + C_2_3*w32 + C_2_4*w43 + C_2_7*w41 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
+                                EM_S[INDEX2(1,4,8)]+=tmp193 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
+                                EM_S[INDEX2(2,4,8)]+=tmp228 + tmp231 + tmp233 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
+                                EM_S[INDEX2(3,4,8)]+=tmp60 + tmp61 + tmp80 + tmp81 + tmp94 + tmp95;
+                                EM_S[INDEX2(4,4,8)]+=-C_0_2*w30 - C_0_3*w46 - C_0_4*w47 - C_0_5*w38 - C_1_1*w31 + C_1_3*w45 + C_1_4*w44 - C_1_6*w39 + C_2_0*w43 + C_2_3*w41 + C_2_4*w40 + C_2_7*w32 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
+                                EM_S[INDEX2(5,4,8)]+=-C_0_2*w46 - C_0_3*w30 - C_0_4*w38 - C_0_5*w47 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
+                                EM_S[INDEX2(6,4,8)]+=C_1_1*w45 - C_1_3*w31 - C_1_4*w39 + C_1_6*w44 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
                                 EM_S[INDEX2(7,4,8)]+=tmp12 + tmp13 + tmp250 + tmp251 + tmp252 + tmp253 + tmp66 + tmp67 + tmp68 + tmp69;
+                                EM_S[INDEX2(0,5,8)]+=tmp190 + tmp193 + tmp195 + tmp196 + tmp197 + tmp199 + tmp224 + tmp225 + tmp226 + tmp227;
+                                EM_S[INDEX2(1,5,8)]+=C_2_1*w40 + C_2_2*w32 + C_2_5*w43 + C_2_6*w41 + tmp72 + tmp73 + tmp82 + tmp83 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
+                                EM_S[INDEX2(2,5,8)]+=tmp60 + tmp61 + tmp63 + tmp64 + tmp94 + tmp95;
+                                EM_S[INDEX2(3,5,8)]+=tmp186 + tmp187 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
+                                EM_S[INDEX2(4,5,8)]+=C_0_2*w30 + C_0_3*w46 + C_0_4*w47 + C_0_5*w38 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp58 + tmp59;
+                                EM_S[INDEX2(5,5,8)]+=C_0_2*w46 + C_0_3*w30 + C_0_4*w38 + C_0_5*w47 - C_1_0*w31 + C_1_2*w45 + C_1_5*w44 - C_1_7*w39 + C_2_1*w43 + C_2_2*w41 + C_2_5*w40 + C_2_6*w32 + tmp135 + tmp136 + tmp208 + tmp211 + tmp212 + tmp213;
+                                EM_S[INDEX2(6,5,8)]+=tmp10 + tmp12 + tmp13 + tmp16 + tmp17 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
                                 EM_S[INDEX2(7,5,8)]+=C_1_0*w45 - C_1_2*w31 - C_1_5*w39 + C_1_7*w44 + tmp141 + tmp147 + tmp170 + tmp171 + tmp172 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178;
+                                EM_S[INDEX2(0,6,8)]+=tmp234 + tmp235 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
+                                EM_S[INDEX2(1,6,8)]+=tmp60 + tmp61 + tmp62 + tmp65 + tmp80 + tmp81;
+                                EM_S[INDEX2(2,6,8)]+=C_2_1*w32 + C_2_2*w40 + C_2_5*w41 + C_2_6*w43 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
+                                EM_S[INDEX2(3,6,8)]+=tmp104 + tmp107 + tmp109 + tmp110 + tmp111 + tmp113 + tmp160 + tmp161 + tmp162 + tmp163;
+                                EM_S[INDEX2(4,6,8)]+=C_1_1*w31 - C_1_3*w45 - C_1_4*w44 + C_1_6*w39 + tmp23 + tmp29 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38;
+                                EM_S[INDEX2(5,6,8)]+=tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
+                                EM_S[INDEX2(6,6,8)]+=-C_0_0*w30 - C_0_1*w46 - C_0_6*w47 - C_0_7*w38 - C_1_1*w45 + C_1_3*w31 + C_1_4*w39 - C_1_6*w44 + C_2_1*w41 + C_2_2*w43 + C_2_5*w32 + C_2_6*w40 + tmp134 + tmp137 + tmp209 + tmp210 + tmp212 + tmp213;
                                 EM_S[INDEX2(7,6,8)]+=-C_0_0*w46 - C_0_1*w30 - C_0_6*w38 - C_0_7*w47 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp130 + tmp131 + tmp148 + tmp149;
+                                EM_S[INDEX2(0,7,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
+                                EM_S[INDEX2(1,7,8)]+=tmp180 + tmp183 + tmp185 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
+                                EM_S[INDEX2(2,7,8)]+=tmp107 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
+                                EM_S[INDEX2(3,7,8)]+=C_2_0*w32 + C_2_3*w40 + C_2_4*w41 + C_2_7*w43 + tmp0 + tmp1 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
+                                EM_S[INDEX2(4,7,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
+                                EM_S[INDEX2(5,7,8)]+=C_1_0*w31 - C_1_2*w45 - C_1_5*w44 + C_1_7*w39 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
+                                EM_S[INDEX2(6,7,8)]+=C_0_0*w30 + C_0_1*w46 + C_0_6*w47 + C_0_7*w38 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
                                 EM_S[INDEX2(7,7,8)]+=C_0_0*w46 + C_0_1*w30 + C_0_6*w38 + C_0_7*w47 - C_1_0*w45 + C_1_2*w31 + C_1_5*w39 - C_1_7*w44 + C_2_0*w41 + C_2_3*w43 + C_2_4*w32 + C_2_7*w40 + tmp150 + tmp151 + tmp166 + tmp167 + tmp168 + tmp169;
                             } else { // constant data
                                 const double wC0 = C_p[0]*w53;
                                 const double wC1 = C_p[1]*w51;
                                 const double wC2 = C_p[2]*w50;
                                 EM_S[INDEX2(0,0,8)]+= 4*wC0 + 4*wC1 - 4*wC2;
-                                EM_S[INDEX2(0,1,8)]+=-4*wC0 + 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(0,2,8)]+= 2*wC0 - 4*wC1 - 2*wC2;
-                                EM_S[INDEX2(0,3,8)]+=-2*wC0 - 2*wC1 -   wC2;
-                                EM_S[INDEX2(0,4,8)]+= 2*wC0 + 2*wC1 + 4*wC2;
-                                EM_S[INDEX2(0,5,8)]+=-2*wC0 +   wC1 + 2*wC2;
-                                EM_S[INDEX2(0,6,8)]+=   wC0 - 2*wC1 + 2*wC2;
-                                EM_S[INDEX2(0,7,8)]+=  -wC0 -   wC1 +   wC2;
                                 EM_S[INDEX2(1,0,8)]+= 4*wC0 + 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(1,1,8)]+=-4*wC0 + 4*wC1 - 4*wC2;
-                                EM_S[INDEX2(1,2,8)]+= 2*wC0 - 2*wC1 -   wC2;
-                                EM_S[INDEX2(1,3,8)]+=-2*wC0 - 4*wC1 - 2*wC2;
-                                EM_S[INDEX2(1,4,8)]+= 2*wC0 +   wC1 + 2*wC2;
-                                EM_S[INDEX2(1,5,8)]+=-2*wC0 + 2*wC1 + 4*wC2;
-                                EM_S[INDEX2(1,6,8)]+=   wC0 -   wC1 +   wC2;
-                                EM_S[INDEX2(1,7,8)]+=  -wC0 - 2*wC1 + 2*wC2;
                                 EM_S[INDEX2(2,0,8)]+= 2*wC0 + 4*wC1 - 2*wC2;
-                                EM_S[INDEX2(2,1,8)]+=-2*wC0 + 2*wC1 -   wC2;
-                                EM_S[INDEX2(2,2,8)]+= 4*wC0 - 4*wC1 - 4*wC2;
-                                EM_S[INDEX2(2,3,8)]+=-4*wC0 - 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(2,4,8)]+=   wC0 + 2*wC1 + 2*wC2;
-                                EM_S[INDEX2(2,5,8)]+=  -wC0 +   wC1 +   wC2;
-                                EM_S[INDEX2(2,6,8)]+= 2*wC0 - 2*wC1 + 4*wC2;
-                                EM_S[INDEX2(2,7,8)]+=-2*wC0 -   wC1 + 2*wC2;
                                 EM_S[INDEX2(3,0,8)]+= 2*wC0 + 2*wC1 -   wC2;
-                                EM_S[INDEX2(3,1,8)]+=-2*wC0 + 4*wC1 - 2*wC2;
-                                EM_S[INDEX2(3,2,8)]+= 4*wC0 - 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(3,3,8)]+=-4*wC0 - 4*wC1 - 4*wC2;
-                                EM_S[INDEX2(3,4,8)]+=   wC0 +   wC1 +   wC2;
-                                EM_S[INDEX2(3,5,8)]+=  -wC0 + 2*wC1 + 2*wC2;
-                                EM_S[INDEX2(3,6,8)]+= 2*wC0 -   wC1 + 2*wC2;
-                                EM_S[INDEX2(3,7,8)]+=-2*wC0 - 2*wC1 + 4*wC2;
                                 EM_S[INDEX2(4,0,8)]+= 2*wC0 + 2*wC1 - 4*wC2;
-                                EM_S[INDEX2(4,1,8)]+=-2*wC0 +   wC1 - 2*wC2;
-                                EM_S[INDEX2(4,2,8)]+=   wC0 - 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(4,3,8)]+=  -wC0 -   wC1 -   wC2;
-                                EM_S[INDEX2(4,4,8)]+= 4*wC0 + 4*wC1 + 4*wC2;
-                                EM_S[INDEX2(4,5,8)]+=-4*wC0 + 2*wC1 + 2*wC2;
-                                EM_S[INDEX2(4,6,8)]+= 2*wC0 - 4*wC1 + 2*wC2;
-                                EM_S[INDEX2(4,7,8)]+=-2*wC0 - 2*wC1 +   wC2;
                                 EM_S[INDEX2(5,0,8)]+= 2*wC0 +   wC1 - 2*wC2;
-                                EM_S[INDEX2(5,1,8)]+=-2*wC0 + 2*wC1 - 4*wC2;
-                                EM_S[INDEX2(5,2,8)]+=   wC0 -   wC1 -   wC2;
-                                EM_S[INDEX2(5,3,8)]+=  -wC0 - 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(5,4,8)]+= 4*wC0 + 2*wC1 + 2*wC2;
-                                EM_S[INDEX2(5,5,8)]+=-4*wC0 + 4*wC1 + 4*wC2;
-                                EM_S[INDEX2(5,6,8)]+= 2*wC0 - 2*wC1 +   wC2;
-                                EM_S[INDEX2(5,7,8)]+=-2*wC0 - 4*wC1 + 2*wC2;
                                 EM_S[INDEX2(6,0,8)]+=   wC0 + 2*wC1 - 2*wC2;
-                                EM_S[INDEX2(6,1,8)]+=  -wC0 +   wC1 -   wC2;
-                                EM_S[INDEX2(6,2,8)]+= 2*wC0 - 2*wC1 - 4*wC2;
-                                EM_S[INDEX2(6,3,8)]+=-2*wC0 -   wC1 - 2*wC2;
-                                EM_S[INDEX2(6,4,8)]+= 2*wC0 + 4*wC1 + 2*wC2;
-                                EM_S[INDEX2(6,5,8)]+=-2*wC0 + 2*wC1 +   wC2;
-                                EM_S[INDEX2(6,6,8)]+= 4*wC0 - 4*wC1 + 4*wC2;
-                                EM_S[INDEX2(6,7,8)]+=-4*wC0 - 2*wC1 + 2*wC2;
                                 EM_S[INDEX2(7,0,8)]+=   wC0 +   wC1 -   wC2;
+                                EM_S[INDEX2(0,1,8)]+=-4*wC0 + 2*wC1 - 2*wC2;
+                                EM_S[INDEX2(1,1,8)]+=-4*wC0 + 4*wC1 - 4*wC2;
+                                EM_S[INDEX2(2,1,8)]+=-2*wC0 + 2*wC1 -   wC2;
+                                EM_S[INDEX2(3,1,8)]+=-2*wC0 + 4*wC1 - 2*wC2;
+                                EM_S[INDEX2(4,1,8)]+=-2*wC0 +   wC1 - 2*wC2;
+                                EM_S[INDEX2(5,1,8)]+=-2*wC0 + 2*wC1 - 4*wC2;
+                                EM_S[INDEX2(6,1,8)]+=  -wC0 +   wC1 -   wC2;
                                 EM_S[INDEX2(7,1,8)]+=  -wC0 + 2*wC1 - 2*wC2;
+                                EM_S[INDEX2(0,2,8)]+= 2*wC0 - 4*wC1 - 2*wC2;
+                                EM_S[INDEX2(1,2,8)]+= 2*wC0 - 2*wC1 -   wC2;
+                                EM_S[INDEX2(2,2,8)]+= 4*wC0 - 4*wC1 - 4*wC2;
+                                EM_S[INDEX2(3,2,8)]+= 4*wC0 - 2*wC1 - 2*wC2;
+                                EM_S[INDEX2(4,2,8)]+=   wC0 - 2*wC1 - 2*wC2;
+                                EM_S[INDEX2(5,2,8)]+=   wC0 -   wC1 -   wC2;
+                                EM_S[INDEX2(6,2,8)]+= 2*wC0 - 2*wC1 - 4*wC2;
                                 EM_S[INDEX2(7,2,8)]+= 2*wC0 -   wC1 - 2*wC2;
+                                EM_S[INDEX2(0,3,8)]+=-2*wC0 - 2*wC1 -   wC2;
+                                EM_S[INDEX2(1,3,8)]+=-2*wC0 - 4*wC1 - 2*wC2;
+                                EM_S[INDEX2(2,3,8)]+=-4*wC0 - 2*wC1 - 2*wC2;
+                                EM_S[INDEX2(3,3,8)]+=-4*wC0 - 4*wC1 - 4*wC2;
+                                EM_S[INDEX2(4,3,8)]+=  -wC0 -   wC1 -   wC2;
+                                EM_S[INDEX2(5,3,8)]+=  -wC0 - 2*wC1 - 2*wC2;
+                                EM_S[INDEX2(6,3,8)]+=-2*wC0 -   wC1 - 2*wC2;
                                 EM_S[INDEX2(7,3,8)]+=-2*wC0 - 2*wC1 - 4*wC2;
+                                EM_S[INDEX2(0,4,8)]+= 2*wC0 + 2*wC1 + 4*wC2;
+                                EM_S[INDEX2(1,4,8)]+= 2*wC0 +   wC1 + 2*wC2;
+                                EM_S[INDEX2(2,4,8)]+=   wC0 + 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(3,4,8)]+=   wC0 +   wC1 +   wC2;
+                                EM_S[INDEX2(4,4,8)]+= 4*wC0 + 4*wC1 + 4*wC2;
+                                EM_S[INDEX2(5,4,8)]+= 4*wC0 + 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(6,4,8)]+= 2*wC0 + 4*wC1 + 2*wC2;
                                 EM_S[INDEX2(7,4,8)]+= 2*wC0 + 2*wC1 +   wC2;
+                                EM_S[INDEX2(0,5,8)]+=-2*wC0 +   wC1 + 2*wC2;
+                                EM_S[INDEX2(1,5,8)]+=-2*wC0 + 2*wC1 + 4*wC2;
+                                EM_S[INDEX2(2,5,8)]+=  -wC0 +   wC1 +   wC2;
+                                EM_S[INDEX2(3,5,8)]+=  -wC0 + 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(4,5,8)]+=-4*wC0 + 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(5,5,8)]+=-4*wC0 + 4*wC1 + 4*wC2;
+                                EM_S[INDEX2(6,5,8)]+=-2*wC0 + 2*wC1 +   wC2;
                                 EM_S[INDEX2(7,5,8)]+=-2*wC0 + 4*wC1 + 2*wC2;
+                                EM_S[INDEX2(0,6,8)]+=   wC0 - 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(1,6,8)]+=   wC0 -   wC1 +   wC2;
+                                EM_S[INDEX2(2,6,8)]+= 2*wC0 - 2*wC1 + 4*wC2;
+                                EM_S[INDEX2(3,6,8)]+= 2*wC0 -   wC1 + 2*wC2;
+                                EM_S[INDEX2(4,6,8)]+= 2*wC0 - 4*wC1 + 2*wC2;
+                                EM_S[INDEX2(5,6,8)]+= 2*wC0 - 2*wC1 +   wC2;
+                                EM_S[INDEX2(6,6,8)]+= 4*wC0 - 4*wC1 + 4*wC2;
                                 EM_S[INDEX2(7,6,8)]+= 4*wC0 - 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(0,7,8)]+=  -wC0 -   wC1 +   wC2;
+                                EM_S[INDEX2(1,7,8)]+=  -wC0 - 2*wC1 + 2*wC2;
+                                EM_S[INDEX2(2,7,8)]+=-2*wC0 -   wC1 + 2*wC2;
+                                EM_S[INDEX2(3,7,8)]+=-2*wC0 - 2*wC1 + 4*wC2;
+                                EM_S[INDEX2(4,7,8)]+=-2*wC0 - 2*wC1 +   wC2;
+                                EM_S[INDEX2(5,7,8)]+=-2*wC0 - 4*wC1 + 2*wC2;
+                                EM_S[INDEX2(6,7,8)]+=-4*wC0 - 2*wC1 + 2*wC2;
                                 EM_S[INDEX2(7,7,8)]+=-4*wC0 - 4*wC1 + 4*wC2;
                             }
                         }
@@ -1822,7 +1835,6 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                         // process D //
                         ///////////////
                         if (!D.isEmpty()) {
-                            add_EM_S=true;
                             const double* D_p=D.getSampleDataRO(e);
                             if (D.actsExpanded()) {
                                 const double D_0 = D_p[0];
@@ -1893,134 +1905,134 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                                 const double tmp57 = w54*(D_6 + D_7);
                                 const double tmp58 = w56*(D_0 + D_1);
                                 EM_S[INDEX2(0,0,8)]+=D_0*w59 + D_7*w60 + tmp49 + tmp50;
-                                EM_S[INDEX2(0,1,8)]+=tmp26 + tmp57 + tmp58;
-                                EM_S[INDEX2(0,2,8)]+=tmp30 + tmp31 + tmp32;
-                                EM_S[INDEX2(0,3,8)]+=tmp10 + tmp11;
-                                EM_S[INDEX2(0,4,8)]+=tmp1 + tmp23 + tmp24;
-                                EM_S[INDEX2(0,5,8)]+=tmp43 + tmp44;
-                                EM_S[INDEX2(0,6,8)]+=tmp55 + tmp56;
-                                EM_S[INDEX2(0,7,8)]+=tmp15;
                                 EM_S[INDEX2(1,0,8)]+=tmp26 + tmp57 + tmp58;
-                                EM_S[INDEX2(1,1,8)]+=D_1*w59 + D_6*w60 + tmp45 + tmp46;
-                                EM_S[INDEX2(1,2,8)]+=tmp10 + tmp11;
-                                EM_S[INDEX2(1,3,8)]+=tmp5 + tmp6 + tmp7;
-                                EM_S[INDEX2(1,4,8)]+=tmp43 + tmp44;
-                                EM_S[INDEX2(1,5,8)]+=tmp17 + tmp19 + tmp20;
-                                EM_S[INDEX2(1,6,8)]+=tmp15;
-                                EM_S[INDEX2(1,7,8)]+=tmp41 + tmp42;
                                 EM_S[INDEX2(2,0,8)]+=tmp30 + tmp31 + tmp32;
-                                EM_S[INDEX2(2,1,8)]+=tmp10 + tmp11;
-                                EM_S[INDEX2(2,2,8)]+=D_2*w59 + D_5*w60 + tmp35 + tmp36;
-                                EM_S[INDEX2(2,3,8)]+=tmp13 + tmp47 + tmp48;
-                                EM_S[INDEX2(2,4,8)]+=tmp55 + tmp56;
-                                EM_S[INDEX2(2,5,8)]+=tmp15;
-                                EM_S[INDEX2(2,6,8)]+=tmp16 + tmp17 + tmp18;
-                                EM_S[INDEX2(2,7,8)]+=tmp21 + tmp22;
                                 EM_S[INDEX2(3,0,8)]+=tmp10 + tmp11;
-                                EM_S[INDEX2(3,1,8)]+=tmp5 + tmp6 + tmp7;
-                                EM_S[INDEX2(3,2,8)]+=tmp13 + tmp47 + tmp48;
-                                EM_S[INDEX2(3,3,8)]+=D_3*w59 + D_4*w60 + tmp28 + tmp29;
-                                EM_S[INDEX2(3,4,8)]+=tmp15;
-                                EM_S[INDEX2(3,5,8)]+=tmp41 + tmp42;
-                                EM_S[INDEX2(3,6,8)]+=tmp21 + tmp22;
-                                EM_S[INDEX2(3,7,8)]+=tmp0 + tmp1 + tmp2;
                                 EM_S[INDEX2(4,0,8)]+=tmp1 + tmp23 + tmp24;
-                                EM_S[INDEX2(4,1,8)]+=tmp43 + tmp44;
-                                EM_S[INDEX2(4,2,8)]+=tmp55 + tmp56;
-                                EM_S[INDEX2(4,3,8)]+=tmp15;
-                                EM_S[INDEX2(4,4,8)]+=D_3*w60 + D_4*w59 + tmp33 + tmp34;
-                                EM_S[INDEX2(4,5,8)]+=tmp12 + tmp13 + tmp14;
-                                EM_S[INDEX2(4,6,8)]+=tmp6 + tmp8 + tmp9;
-                                EM_S[INDEX2(4,7,8)]+=tmp3 + tmp4;
                                 EM_S[INDEX2(5,0,8)]+=tmp43 + tmp44;
-                                EM_S[INDEX2(5,1,8)]+=tmp17 + tmp19 + tmp20;
-                                EM_S[INDEX2(5,2,8)]+=tmp15;
-                                EM_S[INDEX2(5,3,8)]+=tmp41 + tmp42;
-                                EM_S[INDEX2(5,4,8)]+=tmp12 + tmp13 + tmp14;
-                                EM_S[INDEX2(5,5,8)]+=D_2*w60 + D_5*w59 + tmp53 + tmp54;
-                                EM_S[INDEX2(5,6,8)]+=tmp3 + tmp4;
-                                EM_S[INDEX2(5,7,8)]+=tmp31 + tmp39 + tmp40;
                                 EM_S[INDEX2(6,0,8)]+=tmp55 + tmp56;
-                                EM_S[INDEX2(6,1,8)]+=tmp15;
-                                EM_S[INDEX2(6,2,8)]+=tmp16 + tmp17 + tmp18;
-                                EM_S[INDEX2(6,3,8)]+=tmp21 + tmp22;
-                                EM_S[INDEX2(6,4,8)]+=tmp6 + tmp8 + tmp9;
-                                EM_S[INDEX2(6,5,8)]+=tmp3 + tmp4;
-                                EM_S[INDEX2(6,6,8)]+=D_1*w60 + D_6*w59 + tmp51 + tmp52;
-                                EM_S[INDEX2(6,7,8)]+=tmp25 + tmp26 + tmp27;
                                 EM_S[INDEX2(7,0,8)]+=tmp15;
+                                EM_S[INDEX2(0,1,8)]+=tmp26 + tmp57 + tmp58;
+                                EM_S[INDEX2(1,1,8)]+=D_1*w59 + D_6*w60 + tmp45 + tmp46;
+                                EM_S[INDEX2(2,1,8)]+=tmp10 + tmp11;
+                                EM_S[INDEX2(3,1,8)]+=tmp5 + tmp6 + tmp7;
+                                EM_S[INDEX2(4,1,8)]+=tmp43 + tmp44;
+                                EM_S[INDEX2(5,1,8)]+=tmp17 + tmp19 + tmp20;
+                                EM_S[INDEX2(6,1,8)]+=tmp15;
                                 EM_S[INDEX2(7,1,8)]+=tmp41 + tmp42;
+                                EM_S[INDEX2(0,2,8)]+=tmp30 + tmp31 + tmp32;
+                                EM_S[INDEX2(1,2,8)]+=tmp10 + tmp11;
+                                EM_S[INDEX2(2,2,8)]+=D_2*w59 + D_5*w60 + tmp35 + tmp36;
+                                EM_S[INDEX2(3,2,8)]+=tmp13 + tmp47 + tmp48;
+                                EM_S[INDEX2(4,2,8)]+=tmp55 + tmp56;
+                                EM_S[INDEX2(5,2,8)]+=tmp15;
+                                EM_S[INDEX2(6,2,8)]+=tmp16 + tmp17 + tmp18;
                                 EM_S[INDEX2(7,2,8)]+=tmp21 + tmp22;
+                                EM_S[INDEX2(0,3,8)]+=tmp10 + tmp11;
+                                EM_S[INDEX2(1,3,8)]+=tmp5 + tmp6 + tmp7;
+                                EM_S[INDEX2(2,3,8)]+=tmp13 + tmp47 + tmp48;
+                                EM_S[INDEX2(3,3,8)]+=D_3*w59 + D_4*w60 + tmp28 + tmp29;
+                                EM_S[INDEX2(4,3,8)]+=tmp15;
+                                EM_S[INDEX2(5,3,8)]+=tmp41 + tmp42;
+                                EM_S[INDEX2(6,3,8)]+=tmp21 + tmp22;
                                 EM_S[INDEX2(7,3,8)]+=tmp0 + tmp1 + tmp2;
+                                EM_S[INDEX2(0,4,8)]+=tmp1 + tmp23 + tmp24;
+                                EM_S[INDEX2(1,4,8)]+=tmp43 + tmp44;
+                                EM_S[INDEX2(2,4,8)]+=tmp55 + tmp56;
+                                EM_S[INDEX2(3,4,8)]+=tmp15;
+                                EM_S[INDEX2(4,4,8)]+=D_3*w60 + D_4*w59 + tmp33 + tmp34;
+                                EM_S[INDEX2(5,4,8)]+=tmp12 + tmp13 + tmp14;
+                                EM_S[INDEX2(6,4,8)]+=tmp6 + tmp8 + tmp9;
                                 EM_S[INDEX2(7,4,8)]+=tmp3 + tmp4;
+                                EM_S[INDEX2(0,5,8)]+=tmp43 + tmp44;
+                                EM_S[INDEX2(1,5,8)]+=tmp17 + tmp19 + tmp20;
+                                EM_S[INDEX2(2,5,8)]+=tmp15;
+                                EM_S[INDEX2(3,5,8)]+=tmp41 + tmp42;
+                                EM_S[INDEX2(4,5,8)]+=tmp12 + tmp13 + tmp14;
+                                EM_S[INDEX2(5,5,8)]+=D_2*w60 + D_5*w59 + tmp53 + tmp54;
+                                EM_S[INDEX2(6,5,8)]+=tmp3 + tmp4;
                                 EM_S[INDEX2(7,5,8)]+=tmp31 + tmp39 + tmp40;
+                                EM_S[INDEX2(0,6,8)]+=tmp55 + tmp56;
+                                EM_S[INDEX2(1,6,8)]+=tmp15;
+                                EM_S[INDEX2(2,6,8)]+=tmp16 + tmp17 + tmp18;
+                                EM_S[INDEX2(3,6,8)]+=tmp21 + tmp22;
+                                EM_S[INDEX2(4,6,8)]+=tmp6 + tmp8 + tmp9;
+                                EM_S[INDEX2(5,6,8)]+=tmp3 + tmp4;
+                                EM_S[INDEX2(6,6,8)]+=D_1*w60 + D_6*w59 + tmp51 + tmp52;
                                 EM_S[INDEX2(7,6,8)]+=tmp25 + tmp26 + tmp27;
+                                EM_S[INDEX2(0,7,8)]+=tmp15;
+                                EM_S[INDEX2(1,7,8)]+=tmp41 + tmp42;
+                                EM_S[INDEX2(2,7,8)]+=tmp21 + tmp22;
+                                EM_S[INDEX2(3,7,8)]+=tmp0 + tmp1 + tmp2;
+                                EM_S[INDEX2(4,7,8)]+=tmp3 + tmp4;
+                                EM_S[INDEX2(5,7,8)]+=tmp31 + tmp39 + tmp40;
+                                EM_S[INDEX2(6,7,8)]+=tmp25 + tmp26 + tmp27;
                                 EM_S[INDEX2(7,7,8)]+=D_0*w60 + D_7*w59 + tmp37 + tmp38;
                             } else { // constant data
                                 const double wD0 = 8*D_p[0]*w55;
                                 EM_S[INDEX2(0,0,8)]+=8*wD0;
-                                EM_S[INDEX2(0,1,8)]+=4*wD0;
-                                EM_S[INDEX2(0,2,8)]+=4*wD0;
-                                EM_S[INDEX2(0,3,8)]+=2*wD0;
-                                EM_S[INDEX2(0,4,8)]+=4*wD0;
-                                EM_S[INDEX2(0,5,8)]+=2*wD0;
-                                EM_S[INDEX2(0,6,8)]+=2*wD0;
-                                EM_S[INDEX2(0,7,8)]+=wD0;
                                 EM_S[INDEX2(1,0,8)]+=4*wD0;
-                                EM_S[INDEX2(1,1,8)]+=8*wD0;
-                                EM_S[INDEX2(1,2,8)]+=2*wD0;
-                                EM_S[INDEX2(1,3,8)]+=4*wD0;
-                                EM_S[INDEX2(1,4,8)]+=2*wD0;
-                                EM_S[INDEX2(1,5,8)]+=4*wD0;
-                                EM_S[INDEX2(1,6,8)]+=wD0;
-                                EM_S[INDEX2(1,7,8)]+=2*wD0;
                                 EM_S[INDEX2(2,0,8)]+=4*wD0;
-                                EM_S[INDEX2(2,1,8)]+=2*wD0;
-                                EM_S[INDEX2(2,2,8)]+=8*wD0;
-                                EM_S[INDEX2(2,3,8)]+=4*wD0;
-                                EM_S[INDEX2(2,4,8)]+=2*wD0;
-                                EM_S[INDEX2(2,5,8)]+=wD0;
-                                EM_S[INDEX2(2,6,8)]+=4*wD0;
-                                EM_S[INDEX2(2,7,8)]+=2*wD0;
                                 EM_S[INDEX2(3,0,8)]+=2*wD0;
-                                EM_S[INDEX2(3,1,8)]+=4*wD0;
-                                EM_S[INDEX2(3,2,8)]+=4*wD0;
-                                EM_S[INDEX2(3,3,8)]+=8*wD0;
-                                EM_S[INDEX2(3,4,8)]+=wD0;
-                                EM_S[INDEX2(3,5,8)]+=2*wD0;
-                                EM_S[INDEX2(3,6,8)]+=2*wD0;
-                                EM_S[INDEX2(3,7,8)]+=4*wD0;
                                 EM_S[INDEX2(4,0,8)]+=4*wD0;
-                                EM_S[INDEX2(4,1,8)]+=2*wD0;
-                                EM_S[INDEX2(4,2,8)]+=2*wD0;
-                                EM_S[INDEX2(4,3,8)]+=wD0;
-                                EM_S[INDEX2(4,4,8)]+=8*wD0;
-                                EM_S[INDEX2(4,5,8)]+=4*wD0;
-                                EM_S[INDEX2(4,6,8)]+=4*wD0;
-                                EM_S[INDEX2(4,7,8)]+=2*wD0;
                                 EM_S[INDEX2(5,0,8)]+=2*wD0;
-                                EM_S[INDEX2(5,1,8)]+=4*wD0;
-                                EM_S[INDEX2(5,2,8)]+=wD0;
-                                EM_S[INDEX2(5,3,8)]+=2*wD0;
-                                EM_S[INDEX2(5,4,8)]+=4*wD0;
-                                EM_S[INDEX2(5,5,8)]+=8*wD0;
-                                EM_S[INDEX2(5,6,8)]+=2*wD0;
-                                EM_S[INDEX2(5,7,8)]+=4*wD0;
                                 EM_S[INDEX2(6,0,8)]+=2*wD0;
-                                EM_S[INDEX2(6,1,8)]+=wD0;
-                                EM_S[INDEX2(6,2,8)]+=4*wD0;
-                                EM_S[INDEX2(6,3,8)]+=2*wD0;
-                                EM_S[INDEX2(6,4,8)]+=4*wD0;
-                                EM_S[INDEX2(6,5,8)]+=2*wD0;
-                                EM_S[INDEX2(6,6,8)]+=8*wD0;
-                                EM_S[INDEX2(6,7,8)]+=4*wD0;
                                 EM_S[INDEX2(7,0,8)]+=wD0;
+                                EM_S[INDEX2(0,1,8)]+=4*wD0;
+                                EM_S[INDEX2(1,1,8)]+=8*wD0;
+                                EM_S[INDEX2(2,1,8)]+=2*wD0;
+                                EM_S[INDEX2(3,1,8)]+=4*wD0;
+                                EM_S[INDEX2(4,1,8)]+=2*wD0;
+                                EM_S[INDEX2(5,1,8)]+=4*wD0;
+                                EM_S[INDEX2(6,1,8)]+=wD0;
                                 EM_S[INDEX2(7,1,8)]+=2*wD0;
+                                EM_S[INDEX2(0,2,8)]+=4*wD0;
+                                EM_S[INDEX2(1,2,8)]+=2*wD0;
+                                EM_S[INDEX2(2,2,8)]+=8*wD0;
+                                EM_S[INDEX2(3,2,8)]+=4*wD0;
+                                EM_S[INDEX2(4,2,8)]+=2*wD0;
+                                EM_S[INDEX2(5,2,8)]+=wD0;
+                                EM_S[INDEX2(6,2,8)]+=4*wD0;
                                 EM_S[INDEX2(7,2,8)]+=2*wD0;
+                                EM_S[INDEX2(0,3,8)]+=2*wD0;
+                                EM_S[INDEX2(1,3,8)]+=4*wD0;
+                                EM_S[INDEX2(2,3,8)]+=4*wD0;
+                                EM_S[INDEX2(3,3,8)]+=8*wD0;
+                                EM_S[INDEX2(4,3,8)]+=wD0;
+                                EM_S[INDEX2(5,3,8)]+=2*wD0;
+                                EM_S[INDEX2(6,3,8)]+=2*wD0;
                                 EM_S[INDEX2(7,3,8)]+=4*wD0;
+                                EM_S[INDEX2(0,4,8)]+=4*wD0;
+                                EM_S[INDEX2(1,4,8)]+=2*wD0;
+                                EM_S[INDEX2(2,4,8)]+=2*wD0;
+                                EM_S[INDEX2(3,4,8)]+=wD0;
+                                EM_S[INDEX2(4,4,8)]+=8*wD0;
+                                EM_S[INDEX2(5,4,8)]+=4*wD0;
+                                EM_S[INDEX2(6,4,8)]+=4*wD0;
                                 EM_S[INDEX2(7,4,8)]+=2*wD0;
-                                EM_S[INDEX2(7,5,8)]+=4*wD0;
+                                EM_S[INDEX2(0,5,8)]+=2*wD0;
+                                EM_S[INDEX2(1,5,8)]+=4*wD0;
+                                EM_S[INDEX2(2,5,8)]+=wD0;
+                                EM_S[INDEX2(3,5,8)]+=2*wD0;
+                                EM_S[INDEX2(4,5,8)]+=4*wD0;
+                                EM_S[INDEX2(5,5,8)]+=8*wD0;
+                                EM_S[INDEX2(6,5,8)]+=2*wD0;
+                                EM_S[INDEX2(7,5,8)]+=4*wD0;
+                                EM_S[INDEX2(0,6,8)]+=2*wD0;
+                                EM_S[INDEX2(1,6,8)]+=wD0;
+                                EM_S[INDEX2(2,6,8)]+=4*wD0;
+                                EM_S[INDEX2(3,6,8)]+=2*wD0;
+                                EM_S[INDEX2(4,6,8)]+=4*wD0;
+                                EM_S[INDEX2(5,6,8)]+=2*wD0;
+                                EM_S[INDEX2(6,6,8)]+=8*wD0;
                                 EM_S[INDEX2(7,6,8)]+=4*wD0;
+                                EM_S[INDEX2(0,7,8)]+=wD0;
+                                EM_S[INDEX2(1,7,8)]+=2*wD0;
+                                EM_S[INDEX2(2,7,8)]+=2*wD0;
+                                EM_S[INDEX2(3,7,8)]+=4*wD0;
+                                EM_S[INDEX2(4,7,8)]+=2*wD0;
+                                EM_S[INDEX2(5,7,8)]+=4*wD0;
+                                EM_S[INDEX2(6,7,8)]+=4*wD0;
                                 EM_S[INDEX2(7,7,8)]+=8*wD0;
                             }
                         }
@@ -2028,7 +2040,6 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                         // process X //
                         ///////////////
                         if (!X.isEmpty()) {
-                            add_EM_F=true;
                             const double* X_p=X.getSampleDataRO(e);
                             if (X.actsExpanded()) {
                                 const double X_0_0 = X_p[INDEX2(0,0,3)];
@@ -2141,7 +2152,6 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
                         // process Y //
                         ///////////////
                         if (!Y.isEmpty()) {
-                            add_EM_F=true;
                             const double* Y_p=Y.getSampleDataRO(e);
                             if (Y.actsExpanded()) {
                                 const double Y_0 = Y_p[0];
@@ -2190,8 +2200,8 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
 
                         // add to matrix (if add_EM_S) and RHS (if add_EM_F)
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
                     } // end k0 loop
                 } // end k1 loop
             } // end k2 loop
@@ -2199,2899 +2209,1034 @@ void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat, Data& rhs,
     } // end of parallel region
 }
 
-//protected
-void DefaultAssembler3D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
-                                    Data& rhs, const Data& A, const Data& B,
-                                    const Data& C, const Data& D,
-                                    const Data& X, const Data& Y) const
+/****************************************************************************/
+// PDE SINGLE BOUNDARY
+/****************************************************************************/
+
+void DefaultAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
+                                Data& rhs, const Data& d, const Data& y) const
 {
-    const double w6 = m_dx[0]/16;
-    const double w5 = m_dx[1]/16;
-    const double w1 = m_dx[2]/16;
-    const double w14 = m_dx[0]*m_dx[1]/32;
-    const double w13 = m_dx[0]*m_dx[2]/32;
-    const double w12 = m_dx[1]*m_dx[2]/32;
-    const double w18 = m_dx[0]*m_dx[1]*m_dx[2]/64;
-    const double w11 = m_dx[0]*m_dx[1]/(16*m_dx[2]);
-    const double w3 = m_dx[0]*m_dx[2]/(16*m_dx[1]);
-    const double w0 = m_dx[1]*m_dx[2]/(16*m_dx[0]);
+    const double SQRT3 = 1.73205080756887719318;
+    const double w12 = m_dx[0]*m_dx[1]/144;
+    const double w10 = w12*(-SQRT3 + 2);
+    const double w11 = w12*(SQRT3 + 2);
+    const double w13 = w12*(-4*SQRT3 + 7);
+    const double w14 = w12*(4*SQRT3 + 7);
+    const double w7 = m_dx[0]*m_dx[2]/144;
+    const double w5 = w7*(-SQRT3 + 2);
+    const double w6 = w7*(SQRT3 + 2);
+    const double w8 = w7*(-4*SQRT3 + 7);
+    const double w9 = w7*(4*SQRT3 + 7);
+    const double w2 = m_dx[1]*m_dx[2]/144;
+    const double w0 = w2*(-SQRT3 + 2);
+    const double w1 = w2*(SQRT3 + 2);
+    const double w3 = w2*(-4*SQRT3 + 7);
+    const double w4 = w2*(4*SQRT3 + 7);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
+    const bool add_EM_S = !d.isEmpty();
+    const bool add_EM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
-        for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+        vector<double> EM_S(8*8);
+        vector<double> EM_F(8);
+
+        if (domain->m_faceOffset[0] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[1] = 0;
+                EM_F[3] = 0;
+                EM_F[5] = 0;
+                EM_F[7] = 0;
+            }
+
+            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
-            for (index_t k2=k2_0; k2<NE2; k2+=2) {
-                for (index_t k1=0; k1<NE1; ++k1) {
-                    for (index_t k0=0; k0<NE0; ++k0)  {
-                        bool add_EM_S=false;
-                        bool add_EM_F=false;
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                    for (index_t k1=0; k1<NE1; ++k1) {
+                        const index_t e = INDEX2(k1,k2,NE1);
                         ///////////////
-                        // process A //
+                        // process d //
                         ///////////////
-                        if (!A.isEmpty()) {
-                            add_EM_S=true;
-                            const double* A_p=A.getSampleDataRO(e);
-                            const double Aw00 = A_p[INDEX2(0,0,3)]*w0;
-                            const double Aw10 = A_p[INDEX2(1,0,3)]*w1;
-                            const double Aw20 = A_p[INDEX2(2,0,3)]*w5;
-                            const double Aw01 = A_p[INDEX2(0,1,3)]*w1;
-                            const double Aw11 = A_p[INDEX2(1,1,3)]*w3;
-                            const double Aw21 = A_p[INDEX2(2,1,3)]*w6;
-                            const double Aw02 = A_p[INDEX2(0,2,3)]*w5;
-                            const double Aw12 = A_p[INDEX2(1,2,3)]*w6;
-                            const double Aw22 = A_p[INDEX2(2,2,3)]*w11;
-                            EM_S[INDEX2(0,0,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(1,0,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(2,0,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(3,0,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(4,0,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(5,0,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(6,0,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(7,0,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(0,1,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(1,1,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(2,1,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(3,1,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(4,1,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(5,1,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(6,1,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(7,1,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(0,2,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(1,2,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(2,2,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(3,2,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(4,2,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(5,2,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(6,2,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(7,2,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(0,3,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(1,3,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(2,3,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(3,3,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(4,3,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(5,3,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(6,3,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(7,3,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(0,4,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(1,4,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(2,4,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(3,4,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(4,4,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(5,4,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(6,4,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(7,4,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(0,5,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(1,5,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(2,5,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(3,5,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                            EM_S[INDEX2(4,5,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(5,5,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(6,5,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(7,5,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                            EM_S[INDEX2(0,6,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(1,6,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(2,6,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(3,6,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(4,6,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(5,6,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(6,6,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(7,6,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(0,7,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(1,7,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(2,7,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(3,7,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                            EM_S[INDEX2(4,7,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(5,7,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(6,7,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                            EM_S[INDEX2(7,7,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            if (d.actsExpanded()) {
+                                const double d_0 = d_p[0];
+                                const double d_1 = d_p[1];
+                                const double d_2 = d_p[2];
+                                const double d_3 = d_p[3];
+                                const double tmp0 = w0*(d_0 + d_1);
+                                const double tmp1 = w1*(d_2 + d_3);
+                                const double tmp2 = w0*(d_0 + d_2);
+                                const double tmp3 = w1*(d_1 + d_3);
+                                const double tmp4 = w0*(d_1 + d_3);
+                                const double tmp5 = w1*(d_0 + d_2);
+                                const double tmp6 = w0*(d_2 + d_3);
+                                const double tmp7 = w1*(d_0 + d_1);
+                                const double tmp8 = w2*(d_0 + d_3);
+                                const double tmp9 = w2*(d_1 + d_2);
+                                const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
+                                EM_S[INDEX2(0,0,8)] = d_0*w4 + d_3*w3 + tmp9;
+                                EM_S[INDEX2(2,0,8)] = tmp6 + tmp7;
+                                EM_S[INDEX2(4,0,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(6,0,8)] = tmp10;
+                                EM_S[INDEX2(0,2,8)] = tmp6 + tmp7;
+                                EM_S[INDEX2(2,2,8)] = d_1*w4 + d_2*w3 + tmp8;
+                                EM_S[INDEX2(4,2,8)] = tmp10;
+                                EM_S[INDEX2(6,2,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(0,4,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(2,4,8)] = tmp10;
+                                EM_S[INDEX2(4,4,8)] = d_1*w3 + d_2*w4 + tmp8;
+                                EM_S[INDEX2(6,4,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(0,6,8)] = tmp10;
+                                EM_S[INDEX2(2,6,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(4,6,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(6,6,8)] = d_0*w3 + d_3*w4 + tmp9;
+                            } else { // constant data
+                                const double wd0 = 4*d_p[0]*w2;
+                                EM_S[INDEX2(0,0,8)] = 4*wd0;
+                                EM_S[INDEX2(2,0,8)] = 2*wd0;
+                                EM_S[INDEX2(4,0,8)] = 2*wd0;
+                                EM_S[INDEX2(6,0,8)] =   wd0;
+                                EM_S[INDEX2(0,2,8)] = 2*wd0;
+                                EM_S[INDEX2(2,2,8)] = 4*wd0;
+                                EM_S[INDEX2(4,2,8)] =   wd0;
+                                EM_S[INDEX2(6,2,8)] = 2*wd0;
+                                EM_S[INDEX2(0,4,8)] = 2*wd0;
+                                EM_S[INDEX2(2,4,8)] =   wd0;
+                                EM_S[INDEX2(4,4,8)] = 4*wd0;
+                                EM_S[INDEX2(6,4,8)] = 2*wd0;
+                                EM_S[INDEX2(0,6,8)] =   wd0;
+                                EM_S[INDEX2(2,6,8)] = 2*wd0;
+                                EM_S[INDEX2(4,6,8)] = 2*wd0;
+                                EM_S[INDEX2(6,6,8)] = 4*wd0;
+                            }
                         }
                         ///////////////
-                        // process B //
+                        // process y //
                         ///////////////
-                        if (!B.isEmpty()) {
-                            add_EM_S=true;
-                            const double* B_p=B.getSampleDataRO(e);
-                            const double wB0 = B_p[0]*w12;
-                            const double wB1 = B_p[1]*w13;
-                            const double wB2 = B_p[2]*w14;
-                            EM_S[INDEX2(0,0,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,1,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,2,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,3,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,4,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,5,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,6,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(0,7,8)]+=-wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,0,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,1,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,2,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,3,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,4,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,5,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,6,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(1,7,8)]+= wB0 - wB1 - wB2;
-                            EM_S[INDEX2(2,0,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,1,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,2,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,3,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,4,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,5,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,6,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(2,7,8)]+=-wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,0,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,1,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,2,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,3,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,4,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,5,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,6,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(3,7,8)]+= wB0 + wB1 - wB2;
-                            EM_S[INDEX2(4,0,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,1,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,2,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,3,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,4,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,5,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,6,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(4,7,8)]+=-wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,0,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,1,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,2,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,3,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,4,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,5,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,6,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(5,7,8)]+= wB0 - wB1 + wB2;
-                            EM_S[INDEX2(6,0,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,1,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,2,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,3,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,4,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,5,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,6,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(6,7,8)]+=-wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,0,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,1,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,2,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,3,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,4,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,5,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,6,8)]+= wB0 + wB1 + wB2;
-                            EM_S[INDEX2(7,7,8)]+= wB0 + wB1 + wB2;
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                const double y_0 = y_p[0];
+                                const double y_1 = y_p[1];
+                                const double y_2 = y_p[2];
+                                const double y_3 = y_p[3];
+                                const double tmp0 = 6*w2*(y_1 + y_2);
+                                const double tmp1 = 6*w2*(y_0 + y_3);
+                                EM_F[0] = tmp0 + 6*w0*y_3 + 6*w1*y_0;
+                                EM_F[2] = tmp1 + 6*w0*y_2 + 6*w1*y_1;
+                                EM_F[4] = tmp1 + 6*w0*y_1 + 6*w1*y_2;
+                                EM_F[6] = tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                            } else { // constant data
+                                EM_F[0] = 36*w2*y_p[0];
+                                EM_F[2] = 36*w2*y_p[0];
+                                EM_F[4] = 36*w2*y_p[0];
+                                EM_F[6] = 36*w2*y_p[0];
+                            }
                         }
-                        ///////////////
-                        // process C //
-                        ///////////////
-                        if (!C.isEmpty()) {
-                            add_EM_S=true;
-                            const double* C_p=C.getSampleDataRO(e);
-                            const double wC0 = C_p[0]*w12;
-                            const double wC1 = C_p[1]*w13;
-                            const double wC2 = C_p[2]*w14;
-                            EM_S[INDEX2(0,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(1,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(2,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(3,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(4,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(5,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(6,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(7,0,8)]+=-wC0 - wC1 - wC2;
-                            EM_S[INDEX2(0,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(1,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(2,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(3,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(4,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(5,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(6,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(7,1,8)]+= wC0 - wC1 - wC2;
-                            EM_S[INDEX2(0,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(1,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(2,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(3,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(4,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(5,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(6,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(7,2,8)]+=-wC0 + wC1 - wC2;
-                            EM_S[INDEX2(0,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(1,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(2,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(3,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(4,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(5,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(6,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(7,3,8)]+= wC0 + wC1 - wC2;
-                            EM_S[INDEX2(0,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(1,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(2,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(3,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(4,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(5,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(6,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(7,4,8)]+=-wC0 - wC1 + wC2;
-                            EM_S[INDEX2(0,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(1,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(2,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(3,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(4,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(5,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(6,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(7,5,8)]+= wC0 - wC1 + wC2;
-                            EM_S[INDEX2(0,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(1,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(2,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(3,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(4,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(5,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(6,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(7,6,8)]+=-wC0 + wC1 + wC2;
-                            EM_S[INDEX2(0,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(1,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(2,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(3,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(4,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(5,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(6,7,8)]+= wC0 + wC1 + wC2;
-                            EM_S[INDEX2(7,7,8)]+= wC0 + wC1 + wC2;
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k1 loop
+                } // k2 loop
+            } // colouring
+        } // face 0
+
+        if (domain->m_faceOffset[1] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[0] = 0;
+                EM_F[2] = 0;
+                EM_F[4] = 0;
+                EM_F[6] = 0;
+            }
+
+            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+#pragma omp for
+                for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                    for (index_t k1=0; k1<NE1; ++k1) {
+                        const index_t e = domain->m_faceOffset[1]+INDEX2(k1,k2,NE1);
+                        ///////////////
+                        // process d //
+                        ///////////////
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            if (d.actsExpanded()) {
+                                const double d_0 = d_p[0];
+                                const double d_1 = d_p[1];
+                                const double d_2 = d_p[2];
+                                const double d_3 = d_p[3];
+                                const double tmp0 = w0*(d_0 + d_2);
+                                const double tmp1 = w1*(d_1 + d_3);
+                                const double tmp2 = w0*(d_2 + d_3);
+                                const double tmp3 = w1*(d_0 + d_1);
+                                const double tmp4 = w0*(d_1 + d_3);
+                                const double tmp5 = w1*(d_0 + d_2);
+                                const double tmp6 = w2*(d_0 + d_3);
+                                const double tmp7 = w2*(d_1 + d_2);
+                                const double tmp8 = w0*(d_0 + d_1);
+                                const double tmp9 = w1*(d_2 + d_3);
+                                const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
+                                EM_S[INDEX2(1,1,8)] = d_0*w4 + d_3*w3 + tmp7;
+                                EM_S[INDEX2(3,1,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(5,1,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(7,1,8)] = tmp10;
+                                EM_S[INDEX2(1,3,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(3,3,8)] = d_1*w4 + d_2*w3 + tmp6;
+                                EM_S[INDEX2(5,3,8)] = tmp10;
+                                EM_S[INDEX2(7,3,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(1,5,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(3,5,8)] = tmp10;
+                                EM_S[INDEX2(5,5,8)] = d_1*w3 + d_2*w4 + tmp6;
+                                EM_S[INDEX2(7,5,8)] = tmp8 + tmp9;
+                                EM_S[INDEX2(1,7,8)] = tmp10;
+                                EM_S[INDEX2(3,7,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(5,7,8)] = tmp8 + tmp9;
+                                EM_S[INDEX2(7,7,8)] = d_0*w3 + d_3*w4 + tmp7;
+                            } else { // constant data
+                                const double wd0 = 4*d_p[0]*w2;
+                                EM_S[INDEX2(1,1,8)] = 4*wd0;
+                                EM_S[INDEX2(3,1,8)] = 2*wd0;
+                                EM_S[INDEX2(5,1,8)] = 2*wd0;
+                                EM_S[INDEX2(7,1,8)] =   wd0;
+                                EM_S[INDEX2(1,3,8)] = 2*wd0;
+                                EM_S[INDEX2(3,3,8)] = 4*wd0;
+                                EM_S[INDEX2(5,3,8)] =   wd0;
+                                EM_S[INDEX2(7,3,8)] = 2*wd0;
+                                EM_S[INDEX2(1,5,8)] = 2*wd0;
+                                EM_S[INDEX2(3,5,8)] =   wd0;
+                                EM_S[INDEX2(5,5,8)] = 4*wd0;
+                                EM_S[INDEX2(7,5,8)] = 2*wd0;
+                                EM_S[INDEX2(1,7,8)] =   wd0;
+                                EM_S[INDEX2(3,7,8)] = 2*wd0;
+                                EM_S[INDEX2(5,7,8)] = 2*wd0;
+                                EM_S[INDEX2(7,7,8)] = 4*wd0;
+                            }
                         }
                         ///////////////
-                        // process D //
+                        // process y //
                         ///////////////
-                        if (!D.isEmpty()) {
-                            add_EM_S=true;
-                            const double* D_p=D.getSampleDataRO(e);
-                            EM_S[INDEX2(0,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,0,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,1,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,2,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,3,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,4,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,5,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,6,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(0,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(1,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(2,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(3,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(4,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(5,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(6,7,8)]+=D_p[0]*w18;
-                            EM_S[INDEX2(7,7,8)]+=D_p[0]*w18;
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                const double y_0 = y_p[0];
+                                const double y_1 = y_p[1];
+                                const double y_2 = y_p[2];
+                                const double y_3 = y_p[3];
+                                const double tmp0 = 6*w2*(y_1 + y_2);
+                                const double tmp1 = 6*w2*(y_0 + y_3);
+                                EM_F[1] = tmp0 + 6*w0*y_3 + 6*w1*y_0;
+                                EM_F[3] = tmp1 + 6*w0*y_2 + 6*w1*y_1;
+                                EM_F[5] = tmp1 + 6*w0*y_1 + 6*w1*y_2;
+                                EM_F[7] = tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                            } else { // constant data
+                                EM_F[1] = 36*w2*y_p[0];
+                                EM_F[3] = 36*w2*y_p[0];
+                                EM_F[5] = 36*w2*y_p[0];
+                                EM_F[7] = 36*w2*y_p[0];
+                            }
                         }
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(k1+1)-2;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k1 loop
+                } // k2 loop
+            } // colouring
+        } // face 1
+
+        if (domain->m_faceOffset[2] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[2] = 0;
+                EM_F[3] = 0;
+                EM_F[6] = 0;
+                EM_F[7] = 0;
+            }
+
+            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+#pragma omp for
+                for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,NE0);
                         ///////////////
-                        // process X //
+                        // process d //
                         ///////////////
-                        if (!X.isEmpty()) {
-                            add_EM_F=true;
-                            const double* X_p=X.getSampleDataRO(e);
-                            const double wX0 = 8*X_p[0]*w12;
-                            const double wX1 = 8*X_p[1]*w13;
-                            const double wX2 = 8*X_p[2]*w14;
-                            EM_F[0]+=-wX0 - wX1 - wX2;
-                            EM_F[1]+= wX0 - wX1 - wX2;
-                            EM_F[2]+=-wX0 + wX1 - wX2;
-                            EM_F[3]+= wX0 + wX1 - wX2;
-                            EM_F[4]+=-wX0 - wX1 + wX2;
-                            EM_F[5]+= wX0 - wX1 + wX2;
-                            EM_F[6]+=-wX0 + wX1 + wX2;
-                            EM_F[7]+= wX0 + wX1 + wX2;
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            if (d.actsExpanded()) {
+                                const double d_0 = d_p[0];
+                                const double d_1 = d_p[1];
+                                const double d_2 = d_p[2];
+                                const double d_3 = d_p[3];
+                                const double tmp0 = w5*(d_0 + d_1);
+                                const double tmp1 = w6*(d_2 + d_3);
+                                const double tmp2 = w5*(d_0 + d_2);
+                                const double tmp3 = w6*(d_1 + d_3);
+                                const double tmp4 = w5*(d_1 + d_3);
+                                const double tmp5 = w6*(d_0 + d_2);
+                                const double tmp6 = w7*(d_0 + d_3);
+                                const double tmp7 = w7*(d_0 + d_1 + d_2 + d_3);
+                                const double tmp8 = w7*(d_1 + d_2);
+                                const double tmp9 = w5*(d_2 + d_3);
+                                const double tmp10 = w6*(d_0 + d_1);
+                                EM_S[INDEX2(0,0,8)] = d_0*w9 + d_3*w8 + tmp8;
+                                EM_S[INDEX2(1,0,8)] = tmp10 + tmp9;
+                                EM_S[INDEX2(4,0,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(5,0,8)] = tmp7;
+                                EM_S[INDEX2(0,1,8)] = tmp10 + tmp9;
+                                EM_S[INDEX2(1,1,8)] = d_1*w9 + d_2*w8 + tmp6;
+                                EM_S[INDEX2(4,1,8)] = tmp7;
+                                EM_S[INDEX2(5,1,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(0,4,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(1,4,8)] = tmp7;
+                                EM_S[INDEX2(4,4,8)] = d_1*w8 + d_2*w9 + tmp6;
+                                EM_S[INDEX2(5,4,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(0,5,8)] = tmp7;
+                                EM_S[INDEX2(1,5,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(4,5,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(5,5,8)] = d_0*w8 + d_3*w9 + tmp8;
+                            } else { // constant data
+                                const double wd0 = 4*d_p[0]*w7;
+                                EM_S[INDEX2(0,0,8)] = 4*wd0;
+                                EM_S[INDEX2(1,0,8)] = 2*wd0;
+                                EM_S[INDEX2(4,0,8)] = 2*wd0;
+                                EM_S[INDEX2(5,0,8)] =   wd0;
+                                EM_S[INDEX2(0,1,8)] = 2*wd0;
+                                EM_S[INDEX2(1,1,8)] = 4*wd0;
+                                EM_S[INDEX2(4,1,8)] =   wd0;
+                                EM_S[INDEX2(5,1,8)] = 2*wd0;
+                                EM_S[INDEX2(0,4,8)] = 2*wd0;
+                                EM_S[INDEX2(1,4,8)] =   wd0;
+                                EM_S[INDEX2(4,4,8)] = 4*wd0;
+                                EM_S[INDEX2(5,4,8)] = 2*wd0;
+                                EM_S[INDEX2(0,5,8)] =   wd0;
+                                EM_S[INDEX2(1,5,8)] = 2*wd0;
+                                EM_S[INDEX2(4,5,8)] = 2*wd0;
+                                EM_S[INDEX2(5,5,8)] = 4*wd0;
+                            }
                         }
                         ///////////////
-                        // process Y //
+                        // process y //
                         ///////////////
-                        if (!Y.isEmpty()) {
-                            add_EM_F=true;
-                            const double* Y_p=Y.getSampleDataRO(e);
-                            EM_F[0]+=8*Y_p[0]*w18;
-                            EM_F[1]+=8*Y_p[0]*w18;
-                            EM_F[2]+=8*Y_p[0]*w18;
-                            EM_F[3]+=8*Y_p[0]*w18;
-                            EM_F[4]+=8*Y_p[0]*w18;
-                            EM_F[5]+=8*Y_p[0]*w18;
-                            EM_F[6]+=8*Y_p[0]*w18;
-                            EM_F[7]+=8*Y_p[0]*w18;
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                const double y_0 = y_p[0];
+                                const double y_1 = y_p[1];
+                                const double y_2 = y_p[2];
+                                const double y_3 = y_p[3];
+                                const double tmp0 = 6*w7*(y_1 + y_2);
+                                const double tmp1 = 6*w7*(y_0 + y_3);
+                                EM_F[0] = tmp0 + 6*w5*y_3 + 6*w6*y_0;
+                                EM_F[1] = tmp1 + 6*w5*y_2 + 6*w6*y_1;
+                                EM_F[4] = tmp1 + 6*w5*y_1 + 6*w6*y_2;
+                                EM_F[5] = tmp0 + 6*w5*y_0 + 6*w6*y_3;
+                            } else { // constant data
+                                EM_F[0] = 36*w7*y_p[0];
+                                EM_F[1] = 36*w7*y_p[0];
+                                EM_F[4] = 36*w7*y_p[0];
+                                EM_F[5] = 36*w7*y_p[0];
+                            }
                         }
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k2 loop
+            } // colouring
+        } // face 2
 
-                        // add to matrix (if add_EM_S) and RHS (if add_EM_F)
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // end k0 loop
-                } // end k1 loop
-            } // end k2 loop
-        } // end of colouring
-    } // end of parallel region
-}
+        if (domain->m_faceOffset[3] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[0] = 0;
+                EM_F[1] = 0;
+                EM_F[4] = 0;
+                EM_F[5] = 0;
+            }
 
-//protected
-void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
-                                           const Data& A, const Data& B,
-                                           const Data& C, const Data& D,
-                                           const Data& X, const Data& Y) const
-{
-    dim_t numEq, numComp;
-    if (!mat)
-        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
-    else {
-        numEq=mat->getRowBlockSize();
-        numComp=mat->getColumnBlockSize();
-    }
+            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+#pragma omp for
+                for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,NE0);
+                        ///////////////
+                        // process d //
+                        ///////////////
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            if (d.actsExpanded()) {
+                                const double d_0 = d_p[0];
+                                const double d_1 = d_p[1];
+                                const double d_2 = d_p[2];
+                                const double d_3 = d_p[3];
+                                const double tmp0 = w5*(d_0 + d_2);
+                                const double tmp1 = w6*(d_1 + d_3);
+                                const double tmp2 = w5*(d_1 + d_3);
+                                const double tmp3 = w6*(d_0 + d_2);
+                                const double tmp4 = w7*(d_0 + d_1 + d_2 + d_3);
+                                const double tmp5 = w5*(d_0 + d_1);
+                                const double tmp6 = w6*(d_2 + d_3);
+                                const double tmp7 = w7*(d_0 + d_3);
+                                const double tmp8 = w7*(d_1 + d_2);
+                                const double tmp9 = w5*(d_2 + d_3);
+                                const double tmp10 = w6*(d_0 + d_1);
+                                EM_S[INDEX2(2,2,8)] = d_0*w9 + d_3*w8 + tmp8;
+                                EM_S[INDEX2(3,2,8)] = tmp10 + tmp9;
+                                EM_S[INDEX2(6,2,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(7,2,8)] = tmp4;
+                                EM_S[INDEX2(2,3,8)] = tmp10 + tmp9;
+                                EM_S[INDEX2(3,3,8)] = d_1*w9 + d_2*w8 + tmp7;
+                                EM_S[INDEX2(6,3,8)] = tmp4;
+                                EM_S[INDEX2(7,3,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(2,6,8)] = tmp2 + tmp3;
+                                EM_S[INDEX2(3,6,8)] = tmp4;
+                                EM_S[INDEX2(6,6,8)] = d_1*w8 + d_2*w9 + tmp7;
+                                EM_S[INDEX2(7,6,8)] = tmp5 + tmp6;
+                                EM_S[INDEX2(2,7,8)] = tmp4;
+                                EM_S[INDEX2(3,7,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(6,7,8)] = tmp5 + tmp6;
+                                EM_S[INDEX2(7,7,8)] = d_0*w8 + d_3*w9 + tmp8;
+                            } else { // constant data
+                                const double wd0 = 4*d_p[0]*w7;
+                                EM_S[INDEX2(2,2,8)] = 4*wd0;
+                                EM_S[INDEX2(3,2,8)] = 2*wd0;
+                                EM_S[INDEX2(6,2,8)] = 2*wd0;
+                                EM_S[INDEX2(7,2,8)] =   wd0;
+                                EM_S[INDEX2(2,3,8)] = 2*wd0;
+                                EM_S[INDEX2(3,3,8)] = 4*wd0;
+                                EM_S[INDEX2(6,3,8)] =   wd0;
+                                EM_S[INDEX2(7,3,8)] = 2*wd0;
+                                EM_S[INDEX2(2,6,8)] = 2*wd0;
+                                EM_S[INDEX2(3,6,8)] =   wd0;
+                                EM_S[INDEX2(6,6,8)] = 4*wd0;
+                                EM_S[INDEX2(7,6,8)] = 2*wd0;
+                                EM_S[INDEX2(2,7,8)] =   wd0;
+                                EM_S[INDEX2(3,7,8)] = 2*wd0;
+                                EM_S[INDEX2(6,7,8)] = 2*wd0;
+                                EM_S[INDEX2(7,7,8)] = 4*wd0;
+                            }
+                        }
+                        ///////////////
+                        // process y //
+                        ///////////////
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                const double y_0 = y_p[0];
+                                const double y_1 = y_p[1];
+                                const double y_2 = y_p[2];
+                                const double y_3 = y_p[3];
+                                const double tmp0 = 6*w7*(y_1 + y_2);
+                                const double tmp1 = 6*w7*(y_0 + y_3);
+                                EM_F[2] = tmp0 + 6*w5*y_3 + 6*w6*y_0;
+                                EM_F[3] = tmp1 + 6*w5*y_2 + 6*w6*y_1;
+                                EM_F[6] = tmp1 + 6*w5*y_1 + 6*w6*y_2;
+                                EM_F[7] = tmp0 + 6*w5*y_0 + 6*w6*y_3;
+                            } else { // constant data
+                                EM_F[2] = 36*w7*y_p[0];
+                                EM_F[3] = 36*w7*y_p[0];
+                                EM_F[6] = 36*w7*y_p[0];
+                                EM_F[7] = 36*w7*y_p[0];
+                            }
+                        }
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k2 loop
+            } // colouring
+        } // face 3
 
-    const double SQRT3 = 1.73205080756887719318;
-    const double w10 = -m_dx[0]/288;
-    const double w12 = w10*(-SQRT3 - 2);
-    const double w6 = w10*(SQRT3 - 2);
-    const double w18 = w10*(-4*SQRT3 - 7);
-    const double w4 = w10*(-4*SQRT3 + 7);
-    const double w11 = m_dx[1]/288;
-    const double w15 = w11*(SQRT3 + 2);
-    const double w5 = w11*(-SQRT3 + 2);
-    const double w2 = w11*(4*SQRT3 - 7);
-    const double w17 = w11*(4*SQRT3 + 7);
-    const double w8 = m_dx[2]/288;
-    const double w16 = w8*(SQRT3 + 2);
-    const double w1 = w8*(-SQRT3 + 2);
-    const double w20 = w8*(4*SQRT3 - 7);
-    const double w21 = w8*(-4*SQRT3 - 7);
-    const double w54 = -m_dx[0]*m_dx[1]/72;
-    const double w68 = -m_dx[0]*m_dx[1]/48;
-    const double w38 = w68*(-SQRT3 - 3)/36;
-    const double w45 = w68*(SQRT3 - 3)/36;
-    const double w35 = w68*(5*SQRT3 - 9)/36;
-    const double w46 = w68*(-5*SQRT3 - 9)/36;
-    const double w43 = w68*(-19*SQRT3 - 33)/36;
-    const double w44 = w68*(19*SQRT3 - 33)/36;
-    const double w66 = w68*(SQRT3 + 2);
-    const double w70 = w68*(-SQRT3 + 2);
-    const double w56 = -m_dx[0]*m_dx[2]/72;
-    const double w67 = -m_dx[0]*m_dx[2]/48;
-    const double w37 = w67*(-SQRT3 - 3)/36;
-    const double w40 = w67*(SQRT3 - 3)/36;
-    const double w34 = w67*(5*SQRT3 - 9)/36;
-    const double w42 = w67*(-5*SQRT3 - 9)/36;
-    const double w47 = w67*(19*SQRT3 + 33)/36;
-    const double w48 = w67*(-19*SQRT3 + 33)/36;
-    const double w65 = w67*(SQRT3 + 2);
-    const double w71 = w67*(-SQRT3 + 2);
-    const double w55 = -m_dx[1]*m_dx[2]/72;
-    const double w69 = -m_dx[1]*m_dx[2]/48;
-    const double w36 = w69*(SQRT3 - 3)/36;
-    const double w39 = w69*(-SQRT3 - 3)/36;
-    const double w33 = w69*(5*SQRT3 - 9)/36;
-    const double w41 = w69*(-5*SQRT3 - 9)/36;
-    const double w49 = w69*(19*SQRT3 - 33)/36;
-    const double w50 = w69*(-19*SQRT3 - 33)/36;
-    const double w64 = w69*(SQRT3 + 2);
-    const double w72 = w69*(-SQRT3 + 2);
-    const double w58 = m_dx[0]*m_dx[1]*m_dx[2]/1728;
-    const double w60 = w58*(-SQRT3 + 2);
-    const double w61 = w58*(SQRT3 + 2);
-    const double w57 = w58*(-4*SQRT3 + 7);
-    const double w59 = w58*(4*SQRT3 + 7);
-    const double w62 = w58*(15*SQRT3 + 26);
-    const double w63 = w58*(-15*SQRT3 + 26);
-    const double w75 = w58*6*(SQRT3 + 3);
-    const double w76 = w58*6*(-SQRT3 + 3);
-    const double w74 = w58*6*(5*SQRT3 + 9);
-    const double w77 = w58*6*(-5*SQRT3 + 9);
-    const double w13 = -m_dx[0]*m_dx[1]/(288*m_dx[2]);
-    const double w19 = w13*(4*SQRT3 + 7);
-    const double w7 = w13*(-4*SQRT3 + 7);
-    const double w23 = w13*(+SQRT3 - 2);
-    const double w25 = w13*(-SQRT3 - 2);
-    const double w22 = -m_dx[0]*m_dx[2]/(288*m_dx[1]);
-    const double w3 = w22*(SQRT3 - 2);
-    const double w9 = w22*(-SQRT3 - 2);
-    const double w24 = w22*(4*SQRT3 + 7);
-    const double w26 = w22*(-4*SQRT3 + 7);
-    const double w27 = -m_dx[1]*m_dx[2]/(288*m_dx[0]);
-    const double w0 = w27*(SQRT3 - 2);
-    const double w14 = w27*(-SQRT3 - 2);
-    const double w28 = w27*(-4*SQRT3 + 7);
-    const double w29 = w27*(4*SQRT3 + 7);
-    const int NE0 = m_NE[0];
-    const int NE1 = m_NE[1];
-    const int NE2 = m_NE[2];
-    rhs.requireWrite();
+        if (domain->m_faceOffset[4] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[4] = 0;
+                EM_F[5] = 0;
+                EM_F[6] = 0;
+                EM_F[7] = 0;
+            }
 
-#pragma omp parallel
-    {
-        for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
-            for (index_t k2=k2_0; k2<NE2; k2+=2) {
-                for (index_t k1=0; k1<NE1; ++k1) {
-                    for (index_t k0=0; k0<NE0; ++k0)  {
-                        bool add_EM_S=false;
-                        bool add_EM_F=false;
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
                         ///////////////
-                        // process A //
+                        // process d //
                         ///////////////
-                        if (!A.isEmpty()) {
-                            add_EM_S = true;
-                            const double* A_p = A.getSampleDataRO(e);
-                            if (A.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double A_00_0 = A_p[INDEX5(k,0,m,0,0,numEq,3,numComp,3)];
-                                        const double A_01_0 = A_p[INDEX5(k,0,m,1,0,numEq,3,numComp,3)];
-                                        const double A_02_0 = A_p[INDEX5(k,0,m,2,0,numEq,3,numComp,3)];
-                                        const double A_10_0 = A_p[INDEX5(k,1,m,0,0,numEq,3,numComp,3)];
-                                        const double A_11_0 = A_p[INDEX5(k,1,m,1,0,numEq,3,numComp,3)];
-                                        const double A_12_0 = A_p[INDEX5(k,1,m,2,0,numEq,3,numComp,3)];
-                                        const double A_20_0 = A_p[INDEX5(k,2,m,0,0,numEq,3,numComp,3)];
-                                        const double A_21_0 = A_p[INDEX5(k,2,m,1,0,numEq,3,numComp,3)];
-                                        const double A_22_0 = A_p[INDEX5(k,2,m,2,0,numEq,3,numComp,3)];
-                                        const double A_00_1 = A_p[INDEX5(k,0,m,0,1,numEq,3,numComp,3)];
-                                        const double A_01_1 = A_p[INDEX5(k,0,m,1,1,numEq,3,numComp,3)];
-                                        const double A_02_1 = A_p[INDEX5(k,0,m,2,1,numEq,3,numComp,3)];
-                                        const double A_10_1 = A_p[INDEX5(k,1,m,0,1,numEq,3,numComp,3)];
-                                        const double A_11_1 = A_p[INDEX5(k,1,m,1,1,numEq,3,numComp,3)];
-                                        const double A_12_1 = A_p[INDEX5(k,1,m,2,1,numEq,3,numComp,3)];
-                                        const double A_20_1 = A_p[INDEX5(k,2,m,0,1,numEq,3,numComp,3)];
-                                        const double A_21_1 = A_p[INDEX5(k,2,m,1,1,numEq,3,numComp,3)];
-                                        const double A_22_1 = A_p[INDEX5(k,2,m,2,1,numEq,3,numComp,3)];
-                                        const double A_00_2 = A_p[INDEX5(k,0,m,0,2,numEq,3,numComp,3)];
-                                        const double A_01_2 = A_p[INDEX5(k,0,m,1,2,numEq,3,numComp,3)];
-                                        const double A_02_2 = A_p[INDEX5(k,0,m,2,2,numEq,3,numComp,3)];
-                                        const double A_10_2 = A_p[INDEX5(k,1,m,0,2,numEq,3,numComp,3)];
-                                        const double A_11_2 = A_p[INDEX5(k,1,m,1,2,numEq,3,numComp,3)];
-                                        const double A_12_2 = A_p[INDEX5(k,1,m,2,2,numEq,3,numComp,3)];
-                                        const double A_20_2 = A_p[INDEX5(k,2,m,0,2,numEq,3,numComp,3)];
-                                        const double A_21_2 = A_p[INDEX5(k,2,m,1,2,numEq,3,numComp,3)];
-                                        const double A_22_2 = A_p[INDEX5(k,2,m,2,2,numEq,3,numComp,3)];
-                                        const double A_00_3 = A_p[INDEX5(k,0,m,0,3,numEq,3,numComp,3)];
-                                        const double A_01_3 = A_p[INDEX5(k,0,m,1,3,numEq,3,numComp,3)];
-                                        const double A_02_3 = A_p[INDEX5(k,0,m,2,3,numEq,3,numComp,3)];
-                                        const double A_10_3 = A_p[INDEX5(k,1,m,0,3,numEq,3,numComp,3)];
-                                        const double A_11_3 = A_p[INDEX5(k,1,m,1,3,numEq,3,numComp,3)];
-                                        const double A_12_3 = A_p[INDEX5(k,1,m,2,3,numEq,3,numComp,3)];
-                                        const double A_20_3 = A_p[INDEX5(k,2,m,0,3,numEq,3,numComp,3)];
-                                        const double A_21_3 = A_p[INDEX5(k,2,m,1,3,numEq,3,numComp,3)];
-                                        const double A_22_3 = A_p[INDEX5(k,2,m,2,3,numEq,3,numComp,3)];
-                                        const double A_00_4 = A_p[INDEX5(k,0,m,0,4,numEq,3,numComp,3)];
-                                        const double A_01_4 = A_p[INDEX5(k,0,m,1,4,numEq,3,numComp,3)];
-                                        const double A_02_4 = A_p[INDEX5(k,0,m,2,4,numEq,3,numComp,3)];
-                                        const double A_10_4 = A_p[INDEX5(k,1,m,0,4,numEq,3,numComp,3)];
-                                        const double A_11_4 = A_p[INDEX5(k,1,m,1,4,numEq,3,numComp,3)];
-                                        const double A_12_4 = A_p[INDEX5(k,1,m,2,4,numEq,3,numComp,3)];
-                                        const double A_20_4 = A_p[INDEX5(k,2,m,0,4,numEq,3,numComp,3)];
-                                        const double A_21_4 = A_p[INDEX5(k,2,m,1,4,numEq,3,numComp,3)];
-                                        const double A_22_4 = A_p[INDEX5(k,2,m,2,4,numEq,3,numComp,3)];
-                                        const double A_00_5 = A_p[INDEX5(k,0,m,0,5,numEq,3,numComp,3)];
-                                        const double A_01_5 = A_p[INDEX5(k,0,m,1,5,numEq,3,numComp,3)];
-                                        const double A_02_5 = A_p[INDEX5(k,0,m,2,5,numEq,3,numComp,3)];
-                                        const double A_10_5 = A_p[INDEX5(k,1,m,0,5,numEq,3,numComp,3)];
-                                        const double A_11_5 = A_p[INDEX5(k,1,m,1,5,numEq,3,numComp,3)];
-                                        const double A_12_5 = A_p[INDEX5(k,1,m,2,5,numEq,3,numComp,3)];
-                                        const double A_20_5 = A_p[INDEX5(k,2,m,0,5,numEq,3,numComp,3)];
-                                        const double A_21_5 = A_p[INDEX5(k,2,m,1,5,numEq,3,numComp,3)];
-                                        const double A_22_5 = A_p[INDEX5(k,2,m,2,5,numEq,3,numComp,3)];
-                                        const double A_00_6 = A_p[INDEX5(k,0,m,0,6,numEq,3,numComp,3)];
-                                        const double A_01_6 = A_p[INDEX5(k,0,m,1,6,numEq,3,numComp,3)];
-                                        const double A_02_6 = A_p[INDEX5(k,0,m,2,6,numEq,3,numComp,3)];
-                                        const double A_10_6 = A_p[INDEX5(k,1,m,0,6,numEq,3,numComp,3)];
-                                        const double A_11_6 = A_p[INDEX5(k,1,m,1,6,numEq,3,numComp,3)];
-                                        const double A_12_6 = A_p[INDEX5(k,1,m,2,6,numEq,3,numComp,3)];
-                                        const double A_20_6 = A_p[INDEX5(k,2,m,0,6,numEq,3,numComp,3)];
-                                        const double A_21_6 = A_p[INDEX5(k,2,m,1,6,numEq,3,numComp,3)];
-                                        const double A_22_6 = A_p[INDEX5(k,2,m,2,6,numEq,3,numComp,3)];
-                                        const double A_00_7 = A_p[INDEX5(k,0,m,0,7,numEq,3,numComp,3)];
-                                        const double A_01_7 = A_p[INDEX5(k,0,m,1,7,numEq,3,numComp,3)];
-                                        const double A_02_7 = A_p[INDEX5(k,0,m,2,7,numEq,3,numComp,3)];
-                                        const double A_10_7 = A_p[INDEX5(k,1,m,0,7,numEq,3,numComp,3)];
-                                        const double A_11_7 = A_p[INDEX5(k,1,m,1,7,numEq,3,numComp,3)];
-                                        const double A_12_7 = A_p[INDEX5(k,1,m,2,7,numEq,3,numComp,3)];
-                                        const double A_20_7 = A_p[INDEX5(k,2,m,0,7,numEq,3,numComp,3)];
-                                        const double A_21_7 = A_p[INDEX5(k,2,m,1,7,numEq,3,numComp,3)];
-                                        const double A_22_7 = A_p[INDEX5(k,2,m,2,7,numEq,3,numComp,3)];
-                                        const double tmp0 = w18*(-A_12_7 + A_21_3);
-                                        const double tmp1 = w13*(A_22_1 + A_22_2 + A_22_5 + A_22_6);
-                                        const double tmp2 = w11*(-A_02_2 - A_02_5 + A_20_1 + A_20_6);
-                                        const double tmp3 = w14*(A_00_2 + A_00_3 + A_00_6 + A_00_7);
-                                        const double tmp4 = w7*(A_22_0 + A_22_4);
-                                        const double tmp5 = w10*(A_12_1 + A_12_6 - A_21_2 - A_21_5);
-                                        const double tmp6 = w3*(A_11_0 + A_11_2 + A_11_4 + A_11_6);
-                                        const double tmp7 = w1*(A_01_0 + A_01_4 + A_10_0 + A_10_4);
-                                        const double tmp8 = w4*(A_12_0 - A_21_4);
-                                        const double tmp9 = w15*(-A_02_3 - A_02_6 + A_20_2 + A_20_7);
-                                        const double tmp10 = w0*(A_00_0 + A_00_1 + A_00_4 + A_00_5);
-                                        const double tmp11 = w16*(A_01_3 + A_01_7 + A_10_3 + A_10_7);
-                                        const double tmp12 = w9*(A_11_1 + A_11_3 + A_11_5 + A_11_7);
-                                        const double tmp13 = w12*(-A_12_3 - A_12_5 + A_21_1 + A_21_7);
-                                        const double tmp14 = w5*(-A_02_1 - A_02_4 + A_20_0 + A_20_5);
-                                        const double tmp15 = w8*(A_01_1 + A_01_2 + A_01_5 + A_01_6 + A_10_1 + A_10_2 + A_10_5 + A_10_6);
-                                        const double tmp16 = w6*(-A_12_2 - A_12_4 + A_21_0 + A_21_6);
-                                        const double tmp17 = w19*(A_22_3 + A_22_7);
-                                        const double tmp18 = w17*(-A_02_7 + A_20_3);
-                                        const double tmp19 = w2*(A_02_0 - A_20_4);
-                                        const double tmp20 = w13*(-A_22_0 - A_22_1 - A_22_2 - A_22_3 - A_22_4 - A_22_5 - A_22_6 - A_22_7);
-                                        const double tmp21 = w11*(-A_02_1 - A_02_3 - A_02_4 - A_02_6 + A_20_0 + A_20_2 + A_20_5 + A_20_7);
-                                        const double tmp22 = w14*(-A_00_4 - A_00_5 - A_00_6 - A_00_7);
-                                        const double tmp23 = w20*(A_01_2 + A_10_1);
-                                        const double tmp24 = w10*(A_12_2 + A_12_3 + A_12_4 + A_12_5 - A_21_0 - A_21_1 - A_21_6 - A_21_7);
-                                        const double tmp25 = w3*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
-                                        const double tmp26 = w1*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
-                                        const double tmp27 = w15*(-A_02_5 - A_02_7 + A_20_4 + A_20_6);
-                                        const double tmp28 = w0*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
-                                        const double tmp29 = w16*(-A_01_4 - A_01_7 - A_10_4 - A_10_7);
-                                        const double tmp30 = w9*(-A_11_4 - A_11_5 - A_11_6 - A_11_7);
-                                        const double tmp31 = w21*(A_01_5 + A_10_6);
-                                        const double tmp32 = w12*(-A_12_6 - A_12_7 + A_21_4 + A_21_5);
-                                        const double tmp33 = w5*(-A_02_0 - A_02_2 + A_20_1 + A_20_3);
-                                        const double tmp34 = w8*(-A_01_1 - A_01_6 - A_10_2 - A_10_5);
-                                        const double tmp35 = w6*(-A_12_0 - A_12_1 + A_21_2 + A_21_3);
-                                        const double tmp36 = w20*(-A_01_6 + A_10_4);
-                                        const double tmp37 = w18*(A_12_3 - A_21_1);
-                                        const double tmp38 = w11*(-A_02_0 - A_02_2 - A_02_5 - A_02_7 - A_20_0 - A_20_2 - A_20_5 - A_20_7);
-                                        const double tmp39 = w14*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
-                                        const double tmp40 = w26*(A_11_4 + A_11_6);
-                                        const double tmp41 = w0*(A_00_4 + A_00_5 + A_00_6 + A_00_7);
-                                        const double tmp42 = w10*(-A_12_2 - A_12_5 + A_21_0 + A_21_7);
-                                        const double tmp43 = w22*(A_11_0 + A_11_2 + A_11_5 + A_11_7);
-                                        const double tmp44 = w1*(A_01_4 + A_01_7 - A_10_5 - A_10_6);
-                                        const double tmp45 = w25*(A_22_1 + A_22_3 + A_22_5 + A_22_7);
-                                        const double tmp46 = w4*(-A_12_4 + A_21_6);
-                                        const double tmp47 = w15*(-A_02_1 - A_02_3 - A_20_1 - A_20_3);
-                                        const double tmp48 = w21*(-A_01_1 + A_10_3);
-                                        const double tmp49 = w16*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
-                                        const double tmp50 = w5*(-A_02_4 - A_02_6 - A_20_4 - A_20_6);
-                                        const double tmp51 = w12*(A_12_1 + A_12_7 - A_21_3 - A_21_5);
-                                        const double tmp52 = w24*(A_11_1 + A_11_3);
-                                        const double tmp53 = w8*(A_01_2 + A_01_5 - A_10_0 - A_10_7);
-                                        const double tmp54 = w6*(A_12_0 + A_12_6 - A_21_2 - A_21_4);
-                                        const double tmp55 = w23*(A_22_0 + A_22_2 + A_22_4 + A_22_6);
-                                        const double tmp56 = w18*(A_12_4 - A_21_6);
-                                        const double tmp57 = w14*(A_00_4 + A_00_5 + A_00_6 + A_00_7);
-                                        const double tmp58 = w26*(A_11_1 + A_11_3);
-                                        const double tmp59 = w20*(-A_01_1 + A_10_3);
-                                        const double tmp60 = w1*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
-                                        const double tmp61 = w25*(A_22_0 + A_22_2 + A_22_4 + A_22_6);
-                                        const double tmp62 = w4*(-A_12_3 + A_21_1);
-                                        const double tmp63 = w15*(-A_02_4 - A_02_6 - A_20_4 - A_20_6);
-                                        const double tmp64 = w0*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
-                                        const double tmp65 = w16*(A_01_4 + A_01_7 - A_10_5 - A_10_6);
-                                        const double tmp66 = w24*(A_11_4 + A_11_6);
-                                        const double tmp67 = w21*(-A_01_6 + A_10_4);
-                                        const double tmp68 = w12*(A_12_0 + A_12_6 - A_21_2 - A_21_4);
-                                        const double tmp69 = w5*(-A_02_1 - A_02_3 - A_20_1 - A_20_3);
-                                        const double tmp70 = w6*(A_12_1 + A_12_7 - A_21_3 - A_21_5);
-                                        const double tmp71 = w23*(A_22_1 + A_22_3 + A_22_5 + A_22_7);
-                                        const double tmp72 = w20*(A_01_5 + A_10_6);
-                                        const double tmp73 = w14*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
-                                        const double tmp74 = w0*(-A_00_4 - A_00_5 - A_00_6 - A_00_7);
-                                        const double tmp75 = w3*(-A_11_4 - A_11_5 - A_11_6 - A_11_7);
-                                        const double tmp76 = w1*(-A_01_4 - A_01_7 - A_10_4 - A_10_7);
-                                        const double tmp77 = w15*(-A_02_0 - A_02_2 + A_20_1 + A_20_3);
-                                        const double tmp78 = w21*(A_01_2 + A_10_1);
-                                        const double tmp79 = w16*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
-                                        const double tmp80 = w9*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
-                                        const double tmp81 = w12*(-A_12_0 - A_12_1 + A_21_2 + A_21_3);
-                                        const double tmp82 = w5*(-A_02_5 - A_02_7 + A_20_4 + A_20_6);
-                                        const double tmp83 = w6*(-A_12_6 - A_12_7 + A_21_4 + A_21_5);
-                                        const double tmp84 = w6*(-A_12_2 - A_12_3 - A_21_2 - A_21_3);
-                                        const double tmp85 = w11*(A_02_1 + A_02_6 - A_20_0 - A_20_7);
-                                        const double tmp86 = w20*(A_01_3 - A_10_2);
-                                        const double tmp87 = w10*(A_12_0 + A_12_1 + A_12_6 + A_12_7 + A_21_0 + A_21_1 + A_21_6 + A_21_7);
-                                        const double tmp88 = w3*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
-                                        const double tmp89 = w23*(A_22_2 + A_22_3 + A_22_6 + A_22_7);
-                                        const double tmp90 = w1*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
-                                        const double tmp91 = w25*(A_22_0 + A_22_1 + A_22_4 + A_22_5);
-                                        const double tmp92 = w15*(A_02_0 + A_02_5 - A_20_1 - A_20_4);
-                                        const double tmp93 = w21*(A_01_4 - A_10_5);
-                                        const double tmp94 = w16*(-A_01_5 - A_01_6 + A_10_4 + A_10_7);
-                                        const double tmp95 = w28*(A_00_2 + A_00_3);
-                                        const double tmp96 = w12*(-A_12_4 - A_12_5 - A_21_4 - A_21_5);
-                                        const double tmp97 = w29*(A_00_4 + A_00_5);
-                                        const double tmp98 = w5*(A_02_2 + A_02_7 - A_20_3 - A_20_6);
-                                        const double tmp99 = w8*(-A_01_0 - A_01_7 + A_10_1 + A_10_6);
-                                        const double tmp100 = w9*(A_11_4 + A_11_5 + A_11_6 + A_11_7);
-                                        const double tmp101 = w27*(A_00_0 + A_00_1 + A_00_6 + A_00_7);
-                                        const double tmp102 = w17*(A_02_4 - A_20_5);
-                                        const double tmp103 = w2*(-A_02_3 + A_20_2);
-                                        const double tmp104 = w13*(A_22_0 + A_22_1 + A_22_2 + A_22_3 + A_22_4 + A_22_5 + A_22_6 + A_22_7);
-                                        const double tmp105 = w6*(-A_12_4 - A_12_5 - A_21_2 - A_21_3);
-                                        const double tmp106 = w22*(A_11_0 + A_11_1 + A_11_2 + A_11_3 + A_11_4 + A_11_5 + A_11_6 + A_11_7);
-                                        const double tmp107 = w1*(-A_01_2 - A_01_6 - A_10_1 - A_10_5);
-                                        const double tmp108 = w15*(-A_02_1 - A_02_3 - A_20_4 - A_20_6);
-                                        const double tmp109 = w16*(-A_01_1 - A_01_5 - A_10_2 - A_10_6);
-                                        const double tmp110 = w12*(-A_12_2 - A_12_3 - A_21_4 - A_21_5);
-                                        const double tmp111 = w5*(-A_02_4 - A_02_6 - A_20_1 - A_20_3);
-                                        const double tmp112 = w8*(-A_01_0 - A_01_3 - A_01_4 - A_01_7 - A_10_0 - A_10_3 - A_10_4 - A_10_7);
-                                        const double tmp113 = w27*(A_00_0 + A_00_1 + A_00_2 + A_00_3 + A_00_4 + A_00_5 + A_00_6 + A_00_7);
-                                        const double tmp114 = w11*(A_02_0 + A_02_2 + A_02_5 + A_02_7 - A_20_1 - A_20_3 - A_20_4 - A_20_6);
-                                        const double tmp115 = w21*(-A_01_4 - A_10_7);
-                                        const double tmp116 = w20*(-A_01_3 - A_10_0);
-                                        const double tmp117 = w15*(A_02_4 + A_02_6 - A_20_5 - A_20_7);
-                                        const double tmp118 = w16*(A_01_5 + A_01_6 + A_10_5 + A_10_6);
-                                        const double tmp119 = w5*(A_02_1 + A_02_3 - A_20_0 - A_20_2);
-                                        const double tmp120 = w8*(A_01_0 + A_01_7 + A_10_3 + A_10_4);
-                                        const double tmp121 = w1*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
-                                        const double tmp122 = w18*(A_12_2 - A_21_6);
-                                        const double tmp123 = w13*(A_22_0 + A_22_3 + A_22_4 + A_22_7);
-                                        const double tmp124 = w11*(-A_02_0 - A_02_7 + A_20_3 + A_20_4);
-                                        const double tmp125 = w7*(A_22_1 + A_22_5);
-                                        const double tmp126 = w10*(-A_12_3 - A_12_4 + A_21_0 + A_21_7);
-                                        const double tmp127 = w3*(A_11_1 + A_11_3 + A_11_5 + A_11_7);
-                                        const double tmp128 = w1*(-A_01_1 - A_01_5 - A_10_1 - A_10_5);
-                                        const double tmp129 = w4*(-A_12_5 + A_21_1);
-                                        const double tmp130 = w16*(-A_01_2 - A_01_6 - A_10_2 - A_10_6);
-                                        const double tmp131 = w9*(A_11_0 + A_11_2 + A_11_4 + A_11_6);
-                                        const double tmp132 = w19*(A_22_2 + A_22_6);
-                                        const double tmp133 = w17*(-A_02_2 + A_20_6);
-                                        const double tmp134 = w2*(A_02_5 - A_20_1);
-                                        const double tmp135 = w11*(A_02_1 + A_02_3 + A_02_4 + A_02_6 + A_20_1 + A_20_3 + A_20_4 + A_20_6);
-                                        const double tmp136 = w1*(A_01_3 + A_01_7 + A_10_0 + A_10_4);
-                                        const double tmp137 = w15*(A_02_0 + A_02_2 + A_20_5 + A_20_7);
-                                        const double tmp138 = w16*(A_01_0 + A_01_4 + A_10_3 + A_10_7);
-                                        const double tmp139 = w5*(A_02_5 + A_02_7 + A_20_0 + A_20_2);
-                                        const double tmp140 = w18*(A_12_5 - A_21_1);
-                                        const double tmp141 = w14*(A_00_0 + A_00_1 + A_00_4 + A_00_5);
-                                        const double tmp142 = w7*(A_22_2 + A_22_6);
-                                        const double tmp143 = w1*(-A_01_2 - A_01_6 - A_10_2 - A_10_6);
-                                        const double tmp144 = w4*(-A_12_2 + A_21_6);
-                                        const double tmp145 = w15*(-A_02_1 - A_02_4 + A_20_0 + A_20_5);
-                                        const double tmp146 = w0*(A_00_2 + A_00_3 + A_00_6 + A_00_7);
-                                        const double tmp147 = w16*(-A_01_1 - A_01_5 - A_10_1 - A_10_5);
-                                        const double tmp148 = w5*(-A_02_3 - A_02_6 + A_20_2 + A_20_7);
-                                        const double tmp149 = w19*(A_22_1 + A_22_5);
-                                        const double tmp150 = w17*(-A_02_5 + A_20_1);
-                                        const double tmp151 = w2*(A_02_2 - A_20_6);
-                                        const double tmp152 = w18*(A_12_3 - A_21_7);
-                                        const double tmp153 = w11*(A_02_1 + A_02_6 - A_20_2 - A_20_5);
-                                        const double tmp154 = w10*(-A_12_2 - A_12_5 + A_21_1 + A_21_6);
-                                        const double tmp155 = w4*(-A_12_4 + A_21_0);
-                                        const double tmp156 = w15*(A_02_2 + A_02_7 - A_20_3 - A_20_6);
-                                        const double tmp157 = w5*(A_02_0 + A_02_5 - A_20_1 - A_20_4);
-                                        const double tmp158 = w17*(A_02_3 - A_20_7);
-                                        const double tmp159 = w2*(-A_02_4 + A_20_0);
-                                        const double tmp160 = w6*(A_12_6 + A_12_7 + A_21_0 + A_21_1);
-                                        const double tmp161 = w10*(-A_12_2 - A_12_3 - A_12_4 - A_12_5 - A_21_2 - A_21_3 - A_21_4 - A_21_5);
-                                        const double tmp162 = w1*(A_01_0 + A_01_4 + A_10_3 + A_10_7);
-                                        const double tmp163 = w16*(A_01_3 + A_01_7 + A_10_0 + A_10_4);
-                                        const double tmp164 = w12*(A_12_0 + A_12_1 + A_21_6 + A_21_7);
-                                        const double tmp165 = w20*(A_01_6 + A_10_5);
-                                        const double tmp166 = w10*(-A_12_0 - A_12_1 - A_12_6 - A_12_7 + A_21_2 + A_21_3 + A_21_4 + A_21_5);
-                                        const double tmp167 = w15*(A_02_1 + A_02_3 - A_20_0 - A_20_2);
-                                        const double tmp168 = w21*(A_01_1 + A_10_2);
-                                        const double tmp169 = w12*(A_12_2 + A_12_3 - A_21_0 - A_21_1);
-                                        const double tmp170 = w5*(A_02_4 + A_02_6 - A_20_5 - A_20_7);
-                                        const double tmp171 = w8*(-A_01_2 - A_01_5 - A_10_1 - A_10_6);
-                                        const double tmp172 = w6*(A_12_4 + A_12_5 - A_21_6 - A_21_7);
-                                        const double tmp173 = w2*(A_02_1 + A_20_4);
-                                        const double tmp174 = w11*(-A_02_3 - A_02_4 - A_20_1 - A_20_6);
-                                        const double tmp175 = w14*(-A_00_2 - A_00_3 - A_00_6 - A_00_7);
-                                        const double tmp176 = w22*(-A_11_0 - A_11_1 - A_11_2 - A_11_3 - A_11_4 - A_11_5 - A_11_6 - A_11_7);
-                                        const double tmp177 = w1*(A_01_1 + A_01_5 - A_10_0 - A_10_4);
-                                        const double tmp178 = w25*(-A_22_2 - A_22_3 - A_22_6 - A_22_7);
-                                        const double tmp179 = w15*(-A_02_2 - A_02_7 - A_20_2 - A_20_7);
-                                        const double tmp180 = w0*(-A_00_0 - A_00_1 - A_00_4 - A_00_5);
-                                        const double tmp181 = w16*(A_01_2 + A_01_6 - A_10_3 - A_10_7);
-                                        const double tmp182 = w12*(-A_12_6 - A_12_7 + A_21_2 + A_21_3);
-                                        const double tmp183 = w5*(-A_02_0 - A_02_5 - A_20_0 - A_20_5);
-                                        const double tmp184 = w8*(A_01_0 + A_01_3 + A_01_4 + A_01_7 - A_10_1 - A_10_2 - A_10_5 - A_10_6);
-                                        const double tmp185 = w6*(-A_12_0 - A_12_1 + A_21_4 + A_21_5);
-                                        const double tmp186 = w17*(-A_02_6 - A_20_3);
-                                        const double tmp187 = w23*(-A_22_0 - A_22_1 - A_22_4 - A_22_5);
-                                        const double tmp188 = w18*(A_12_4 - A_21_0);
-                                        const double tmp189 = w7*(A_22_3 + A_22_7);
-                                        const double tmp190 = w1*(A_01_3 + A_01_7 + A_10_3 + A_10_7);
-                                        const double tmp191 = w4*(-A_12_3 + A_21_7);
-                                        const double tmp192 = w16*(A_01_0 + A_01_4 + A_10_0 + A_10_4);
-                                        const double tmp193 = w19*(A_22_0 + A_22_4);
-                                        const double tmp194 = w17*(A_02_4 - A_20_0);
-                                        const double tmp195 = w2*(-A_02_3 + A_20_7);
-                                        const double tmp196 = w20*(-A_01_7 - A_10_4);
-                                        const double tmp197 = w21*(-A_01_0 - A_10_3);
-                                        const double tmp198 = w16*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
-                                        const double tmp199 = w8*(A_01_3 + A_01_4 + A_10_0 + A_10_7);
-                                        const double tmp200 = w1*(A_01_5 + A_01_6 + A_10_5 + A_10_6);
-                                        const double tmp201 = w27*(A_00_2 + A_00_3 + A_00_4 + A_00_5);
-                                        const double tmp202 = w11*(-A_02_2 - A_02_5 + A_20_3 + A_20_4);
-                                        const double tmp203 = w20*(A_01_0 - A_10_1);
-                                        const double tmp204 = w23*(A_22_0 + A_22_1 + A_22_4 + A_22_5);
-                                        const double tmp205 = w25*(A_22_2 + A_22_3 + A_22_6 + A_22_7);
-                                        const double tmp206 = w21*(A_01_7 - A_10_6);
-                                        const double tmp207 = w12*(A_12_6 + A_12_7 + A_21_6 + A_21_7);
-                                        const double tmp208 = w28*(A_00_0 + A_00_1);
-                                        const double tmp209 = w29*(A_00_6 + A_00_7);
-                                        const double tmp210 = w8*(-A_01_3 - A_01_4 + A_10_2 + A_10_5);
-                                        const double tmp211 = w6*(A_12_0 + A_12_1 + A_21_0 + A_21_1);
-                                        const double tmp212 = w17*(-A_02_7 + A_20_6);
-                                        const double tmp213 = w2*(A_02_0 - A_20_1);
-                                        const double tmp214 = w13*(-A_22_1 - A_22_2 - A_22_5 - A_22_6);
-                                        const double tmp215 = w22*(-A_11_0 - A_11_2 - A_11_5 - A_11_7);
-                                        const double tmp216 = w8*(A_01_0 + A_01_7 + A_10_0 + A_10_7);
-                                        const double tmp217 = w27*(-A_00_0 - A_00_1 - A_00_6 - A_00_7);
-                                        const double tmp218 = w17*(-A_02_3 - A_20_3);
-                                        const double tmp219 = w2*(A_02_4 + A_20_4);
-                                        const double tmp220 = w11*(-A_02_1 - A_02_6 - A_20_1 - A_20_6);
-                                        const double tmp221 = w26*(-A_11_4 - A_11_6);
-                                        const double tmp222 = w10*(A_12_2 + A_12_5 + A_21_2 + A_21_5);
-                                        const double tmp223 = w20*(-A_01_4 - A_10_4);
-                                        const double tmp224 = w21*(-A_01_3 - A_10_3);
-                                        const double tmp225 = w6*(-A_12_0 - A_12_6 - A_21_0 - A_21_6);
-                                        const double tmp226 = w7*(-A_22_0 - A_22_4);
-                                        const double tmp227 = w24*(-A_11_1 - A_11_3);
-                                        const double tmp228 = w19*(-A_22_3 - A_22_7);
-                                        const double tmp229 = w18*(-A_12_3 - A_21_3);
-                                        const double tmp230 = w4*(A_12_4 + A_21_4);
-                                        const double tmp231 = w28*(-A_00_4 - A_00_5);
-                                        const double tmp232 = w12*(-A_12_1 - A_12_7 - A_21_1 - A_21_7);
-                                        const double tmp233 = w29*(-A_00_2 - A_00_3);
-                                        const double tmp234 = w20*(-A_01_5 + A_10_7);
-                                        const double tmp235 = w18*(-A_12_0 + A_21_2);
-                                        const double tmp236 = w26*(A_11_5 + A_11_7);
-                                        const double tmp237 = w10*(A_12_1 + A_12_6 - A_21_3 - A_21_4);
-                                        const double tmp238 = w22*(A_11_1 + A_11_3 + A_11_4 + A_11_6);
-                                        const double tmp239 = w4*(A_12_7 - A_21_5);
-                                        const double tmp240 = w15*(A_02_0 + A_02_2 + A_20_0 + A_20_2);
-                                        const double tmp241 = w21*(-A_01_2 + A_10_0);
-                                        const double tmp242 = w5*(A_02_5 + A_02_7 + A_20_5 + A_20_7);
-                                        const double tmp243 = w12*(-A_12_2 - A_12_4 + A_21_0 + A_21_6);
-                                        const double tmp244 = w24*(A_11_0 + A_11_2);
-                                        const double tmp245 = w8*(A_01_1 + A_01_6 - A_10_3 - A_10_4);
-                                        const double tmp246 = w6*(-A_12_3 - A_12_5 + A_21_1 + A_21_7);
-                                        const double tmp247 = w11*(A_02_3 + A_02_4 - A_20_2 - A_20_5);
-                                        const double tmp248 = w20*(-A_01_1 + A_10_0);
-                                        const double tmp249 = w21*(-A_01_6 + A_10_7);
-                                        const double tmp250 = w8*(A_01_2 + A_01_5 - A_10_3 - A_10_4);
-                                        const double tmp251 = w17*(A_02_6 - A_20_7);
-                                        const double tmp252 = w2*(-A_02_1 + A_20_0);
-                                        const double tmp253 = w17*(-A_02_4 - A_20_4);
-                                        const double tmp254 = w2*(A_02_3 + A_20_3);
-                                        const double tmp255 = w26*(-A_11_1 - A_11_3);
-                                        const double tmp256 = w20*(-A_01_3 - A_10_3);
-                                        const double tmp257 = w21*(-A_01_4 - A_10_4);
-                                        const double tmp258 = w6*(-A_12_1 - A_12_7 - A_21_1 - A_21_7);
-                                        const double tmp259 = w7*(-A_22_3 - A_22_7);
-                                        const double tmp260 = w15*(-A_02_0 - A_02_5 - A_20_0 - A_20_5);
-                                        const double tmp261 = w24*(-A_11_4 - A_11_6);
-                                        const double tmp262 = w19*(-A_22_0 - A_22_4);
-                                        const double tmp263 = w18*(-A_12_4 - A_21_4);
-                                        const double tmp264 = w4*(A_12_3 + A_21_3);
-                                        const double tmp265 = w28*(-A_00_2 - A_00_3);
-                                        const double tmp266 = w12*(-A_12_0 - A_12_6 - A_21_0 - A_21_6);
-                                        const double tmp267 = w5*(-A_02_2 - A_02_7 - A_20_2 - A_20_7);
-                                        const double tmp268 = w29*(-A_00_4 - A_00_5);
-                                        const double tmp269 = w11*(A_02_2 + A_02_5 + A_20_0 + A_20_7);
-                                        const double tmp270 = w1*(-A_01_0 - A_01_4 + A_10_1 + A_10_5);
-                                        const double tmp271 = w15*(A_02_3 + A_02_6 + A_20_3 + A_20_6);
-                                        const double tmp272 = w16*(-A_01_3 - A_01_7 + A_10_2 + A_10_6);
-                                        const double tmp273 = w5*(A_02_1 + A_02_4 + A_20_1 + A_20_4);
-                                        const double tmp274 = w8*(-A_01_1 - A_01_2 - A_01_5 - A_01_6 + A_10_0 + A_10_3 + A_10_4 + A_10_7);
-                                        const double tmp275 = w17*(A_02_7 + A_20_2);
-                                        const double tmp276 = w2*(-A_02_0 - A_20_5);
-                                        const double tmp277 = w18*(-A_12_1 + A_21_5);
-                                        const double tmp278 = w11*(A_02_3 + A_02_4 - A_20_0 - A_20_7);
-                                        const double tmp279 = w10*(A_12_0 + A_12_7 - A_21_3 - A_21_4);
-                                        const double tmp280 = w4*(A_12_6 - A_21_2);
-                                        const double tmp281 = w17*(A_02_1 - A_20_5);
-                                        const double tmp282 = w2*(-A_02_6 + A_20_2);
-                                        const double tmp283 = w11*(A_02_0 + A_02_7 + A_20_2 + A_20_5);
-                                        const double tmp284 = w12*(A_12_2 + A_12_3 - A_21_6 - A_21_7);
-                                        const double tmp285 = w6*(A_12_4 + A_12_5 - A_21_0 - A_21_1);
-                                        const double tmp286 = w17*(A_02_2 + A_20_7);
-                                        const double tmp287 = w2*(-A_02_5 - A_20_0);
-                                        const double tmp288 = w13*(-A_22_0 - A_22_3 - A_22_4 - A_22_7);
-                                        const double tmp289 = w22*(-A_11_1 - A_11_3 - A_11_4 - A_11_6);
-                                        const double tmp290 = w8*(-A_01_1 - A_01_6 - A_10_1 - A_10_6);
-                                        const double tmp291 = w17*(A_02_2 + A_20_2);
-                                        const double tmp292 = w2*(-A_02_5 - A_20_5);
-                                        const double tmp293 = w11*(A_02_0 + A_02_7 + A_20_0 + A_20_7);
-                                        const double tmp294 = w26*(-A_11_5 - A_11_7);
-                                        const double tmp295 = w10*(A_12_3 + A_12_4 + A_21_3 + A_21_4);
-                                        const double tmp296 = w20*(A_01_5 + A_10_5);
-                                        const double tmp297 = w21*(A_01_2 + A_10_2);
-                                        const double tmp298 = w7*(-A_22_1 - A_22_5);
-                                        const double tmp299 = w24*(-A_11_0 - A_11_2);
-                                        const double tmp300 = w19*(-A_22_2 - A_22_6);
-                                        const double tmp301 = w18*(-A_12_2 - A_21_2);
-                                        const double tmp302 = w4*(A_12_5 + A_21_5);
-                                        const double tmp303 = w8*(A_01_3 + A_01_4 + A_10_3 + A_10_4);
-                                        const double tmp304 = w27*(-A_00_2 - A_00_3 - A_00_4 - A_00_5);
-                                        const double tmp305 = w17*(A_02_7 + A_20_7);
-                                        const double tmp306 = w2*(-A_02_0 - A_20_0);
-                                        const double tmp307 = w11*(A_02_2 + A_02_5 + A_20_2 + A_20_5);
-                                        const double tmp308 = w26*(-A_11_0 - A_11_2);
-                                        const double tmp309 = w10*(-A_12_1 - A_12_6 - A_21_1 - A_21_6);
-                                        const double tmp310 = w20*(-A_01_0 - A_10_0);
-                                        const double tmp311 = w21*(-A_01_7 - A_10_7);
-                                        const double tmp312 = w6*(A_12_2 + A_12_4 + A_21_2 + A_21_4);
-                                        const double tmp313 = w24*(-A_11_5 - A_11_7);
-                                        const double tmp314 = w18*(A_12_7 + A_21_7);
-                                        const double tmp315 = w4*(-A_12_0 - A_21_0);
-                                        const double tmp316 = w28*(-A_00_0 - A_00_1);
-                                        const double tmp317 = w12*(A_12_3 + A_12_5 + A_21_3 + A_21_5);
-                                        const double tmp318 = w29*(-A_00_6 - A_00_7);
-                                        const double tmp319 = w18*(-A_12_7 + A_21_5);
-                                        const double tmp320 = w26*(A_11_0 + A_11_2);
-                                        const double tmp321 = w21*(-A_01_5 + A_10_7);
-                                        const double tmp322 = w20*(-A_01_2 + A_10_0);
-                                        const double tmp323 = w4*(A_12_0 - A_21_2);
-                                        const double tmp324 = w15*(A_02_5 + A_02_7 + A_20_5 + A_20_7);
-                                        const double tmp325 = w24*(A_11_5 + A_11_7);
-                                        const double tmp326 = w5*(A_02_0 + A_02_2 + A_20_0 + A_20_2);
-                                        const double tmp327 = w18*(A_12_7 + A_21_1);
-                                        const double tmp328 = w10*(-A_12_1 - A_12_6 - A_21_0 - A_21_7);
-                                        const double tmp329 = w3*(-A_11_0 - A_11_2 - A_11_4 - A_11_6);
-                                        const double tmp330 = w1*(A_01_2 + A_01_6 - A_10_0 - A_10_4);
-                                        const double tmp331 = w4*(-A_12_0 - A_21_6);
-                                        const double tmp332 = w25*(-A_22_1 - A_22_3 - A_22_5 - A_22_7);
-                                        const double tmp333 = w15*(-A_02_5 - A_02_7 + A_20_1 + A_20_3);
-                                        const double tmp334 = w16*(A_01_1 + A_01_5 - A_10_3 - A_10_7);
-                                        const double tmp335 = w9*(-A_11_1 - A_11_3 - A_11_5 - A_11_7);
-                                        const double tmp336 = w5*(-A_02_0 - A_02_2 + A_20_4 + A_20_6);
-                                        const double tmp337 = w27*(-A_00_0 - A_00_1 - A_00_2 - A_00_3 - A_00_4 - A_00_5 - A_00_6 - A_00_7);
-                                        const double tmp338 = w23*(-A_22_0 - A_22_2 - A_22_4 - A_22_6);
-                                        const double tmp339 = w14*(-A_00_0 - A_00_1 - A_00_4 - A_00_5);
-                                        const double tmp340 = w23*(-A_22_2 - A_22_3 - A_22_6 - A_22_7);
-                                        const double tmp341 = w1*(A_01_2 + A_01_6 - A_10_3 - A_10_7);
-                                        const double tmp342 = w25*(-A_22_0 - A_22_1 - A_22_4 - A_22_5);
-                                        const double tmp343 = w15*(A_02_1 + A_02_4 + A_20_1 + A_20_4);
-                                        const double tmp344 = w0*(-A_00_2 - A_00_3 - A_00_6 - A_00_7);
-                                        const double tmp345 = w16*(A_01_1 + A_01_5 - A_10_0 - A_10_4);
-                                        const double tmp346 = w12*(A_12_4 + A_12_5 - A_21_0 - A_21_1);
-                                        const double tmp347 = w5*(A_02_3 + A_02_6 + A_20_3 + A_20_6);
-                                        const double tmp348 = w6*(A_12_2 + A_12_3 - A_21_6 - A_21_7);
-                                        const double tmp349 = w17*(A_02_5 + A_20_0);
-                                        const double tmp350 = w2*(-A_02_2 - A_20_7);
-                                        const double tmp351 = w8*(-A_01_2 - A_01_5 - A_10_2 - A_10_5);
-                                        const double tmp352 = w17*(-A_02_1 - A_20_1);
-                                        const double tmp353 = w2*(A_02_6 + A_20_6);
-                                        const double tmp354 = w11*(-A_02_3 - A_02_4 - A_20_3 - A_20_4);
-                                        const double tmp355 = w10*(-A_12_0 - A_12_7 - A_21_0 - A_21_7);
-                                        const double tmp356 = w20*(A_01_6 + A_10_6);
-                                        const double tmp357 = w21*(A_01_1 + A_10_1);
-                                        const double tmp358 = w7*(-A_22_2 - A_22_6);
-                                        const double tmp359 = w19*(-A_22_1 - A_22_5);
-                                        const double tmp360 = w18*(A_12_1 + A_21_1);
-                                        const double tmp361 = w4*(-A_12_6 - A_21_6);
-                                        const double tmp362 = w28*(-A_00_6 - A_00_7);
-                                        const double tmp363 = w29*(-A_00_0 - A_00_1);
-                                        const double tmp364 = w2*(A_02_4 + A_20_1);
-                                        const double tmp365 = w11*(-A_02_1 - A_02_6 - A_20_3 - A_20_4);
-                                        const double tmp366 = w17*(-A_02_3 - A_20_6);
-                                        const double tmp367 = w2*(A_02_5 - A_20_4);
-                                        const double tmp368 = w6*(-A_12_4 - A_12_5 - A_21_4 - A_21_5);
-                                        const double tmp369 = w11*(-A_02_0 - A_02_7 + A_20_1 + A_20_6);
-                                        const double tmp370 = w20*(-A_01_5 + A_10_4);
-                                        const double tmp371 = w3*(A_11_4 + A_11_5 + A_11_6 + A_11_7);
-                                        const double tmp372 = w12*(-A_12_2 - A_12_3 - A_21_2 - A_21_3);
-                                        const double tmp373 = w21*(-A_01_2 + A_10_3);
-                                        const double tmp374 = w9*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
-                                        const double tmp375 = w29*(A_00_2 + A_00_3);
-                                        const double tmp376 = w8*(A_01_1 + A_01_6 - A_10_0 - A_10_7);
-                                        const double tmp377 = w28*(A_00_4 + A_00_5);
-                                        const double tmp378 = w17*(-A_02_2 + A_20_3);
-                                        const double tmp379 = w17*(A_02_0 + A_20_0);
-                                        const double tmp380 = w2*(-A_02_7 - A_20_7);
-                                        const double tmp381 = w20*(-A_01_7 - A_10_7);
-                                        const double tmp382 = w21*(-A_01_0 - A_10_0);
-                                        const double tmp383 = w6*(A_12_3 + A_12_5 + A_21_3 + A_21_5);
-                                        const double tmp384 = w18*(A_12_0 + A_21_0);
-                                        const double tmp385 = w4*(-A_12_7 - A_21_7);
-                                        const double tmp386 = w12*(A_12_2 + A_12_4 + A_21_2 + A_21_4);
-                                        const double tmp387 = w17*(-A_02_6 - A_20_6);
-                                        const double tmp388 = w2*(A_02_1 + A_20_1);
-                                        const double tmp389 = w20*(A_01_1 + A_10_1);
-                                        const double tmp390 = w21*(A_01_6 + A_10_6);
-                                        const double tmp391 = w18*(A_12_6 + A_21_6);
-                                        const double tmp392 = w4*(-A_12_1 - A_21_1);
-                                        const double tmp393 = w2*(A_02_3 + A_20_6);
-                                        const double tmp394 = w1*(-A_01_3 - A_01_7 + A_10_2 + A_10_6);
-                                        const double tmp395 = w16*(-A_01_0 - A_01_4 + A_10_1 + A_10_5);
-                                        const double tmp396 = w17*(-A_02_4 - A_20_1);
-                                        const double tmp397 = w18*(-A_12_5 - A_21_3);
-                                        const double tmp398 = w10*(A_12_3 + A_12_4 + A_21_2 + A_21_5);
-                                        const double tmp399 = w1*(-A_01_0 - A_01_4 + A_10_2 + A_10_6);
-                                        const double tmp400 = w4*(A_12_2 + A_21_4);
-                                        const double tmp401 = w16*(-A_01_3 - A_01_7 + A_10_1 + A_10_5);
-                                        const double tmp402 = w20*(-A_01_2 + A_10_3);
-                                        const double tmp403 = w21*(-A_01_5 + A_10_4);
-                                        const double tmp404 = w17*(-A_02_5 + A_20_4);
-                                        const double tmp405 = w2*(A_02_2 - A_20_3);
-                                        const double tmp406 = w18*(-A_12_0 + A_21_4);
-                                        const double tmp407 = w4*(A_12_7 - A_21_3);
-                                        const double tmp408 = w17*(-A_02_0 + A_20_4);
-                                        const double tmp409 = w2*(A_02_7 - A_20_3);
-                                        const double tmp410 = w17*(A_02_5 + A_20_5);
-                                        const double tmp411 = w2*(-A_02_2 - A_20_2);
-                                        const double tmp412 = w20*(A_01_2 + A_10_2);
-                                        const double tmp413 = w21*(A_01_5 + A_10_5);
-                                        const double tmp414 = w18*(-A_12_5 - A_21_5);
-                                        const double tmp415 = w4*(A_12_2 + A_21_2);
-                                        const double tmp416 = w12*(-A_12_0 - A_12_1 + A_21_4 + A_21_5);
-                                        const double tmp417 = w6*(-A_12_6 - A_12_7 + A_21_2 + A_21_3);
-                                        const double tmp418 = w17*(A_02_0 + A_20_5);
-                                        const double tmp419 = w2*(-A_02_7 - A_20_2);
-                                        const double tmp420 = w18*(-A_12_4 - A_21_2);
-                                        const double tmp421 = w10*(A_12_2 + A_12_5 + A_21_3 + A_21_4);
-                                        const double tmp422 = w3*(-A_11_1 - A_11_3 - A_11_5 - A_11_7);
-                                        const double tmp423 = w1*(A_01_1 + A_01_5 - A_10_3 - A_10_7);
-                                        const double tmp424 = w25*(-A_22_0 - A_22_2 - A_22_4 - A_22_6);
-                                        const double tmp425 = w4*(A_12_3 + A_21_5);
-                                        const double tmp426 = w15*(A_02_4 + A_02_6 - A_20_0 - A_20_2);
-                                        const double tmp427 = w16*(A_01_2 + A_01_6 - A_10_0 - A_10_4);
-                                        const double tmp428 = w9*(-A_11_0 - A_11_2 - A_11_4 - A_11_6);
-                                        const double tmp429 = w5*(A_02_1 + A_02_3 - A_20_5 - A_20_7);
-                                        const double tmp430 = w23*(-A_22_1 - A_22_3 - A_22_5 - A_22_7);
-                                        const double tmp431 = w18*(A_12_5 - A_21_7);
-                                        const double tmp432 = w10*(-A_12_3 - A_12_4 + A_21_1 + A_21_6);
-                                        const double tmp433 = w21*(A_01_7 - A_10_5);
-                                        const double tmp434 = w20*(A_01_0 - A_10_2);
-                                        const double tmp435 = w4*(-A_12_2 + A_21_0);
-                                        const double tmp436 = w8*(-A_01_3 - A_01_4 + A_10_1 + A_10_6);
-                                        const double tmp437 = w2*(-A_02_4 + A_20_5);
-                                        const double tmp438 = w20*(A_01_4 - A_10_5);
-                                        const double tmp439 = w21*(A_01_3 - A_10_2);
-                                        const double tmp440 = w16*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
-                                        const double tmp441 = w1*(-A_01_5 - A_01_6 + A_10_4 + A_10_7);
-                                        const double tmp442 = w17*(A_02_3 - A_20_2);
-                                        const double tmp443 = w20*(-A_01_4 - A_10_7);
-                                        const double tmp444 = w21*(-A_01_3 - A_10_0);
-                                        const double tmp445 = w18*(A_12_6 + A_21_0);
-                                        const double tmp446 = w10*(-A_12_0 - A_12_7 - A_21_1 - A_21_6);
-                                        const double tmp447 = w1*(-A_01_3 - A_01_7 + A_10_1 + A_10_5);
-                                        const double tmp448 = w4*(-A_12_1 - A_21_7);
-                                        const double tmp449 = w16*(-A_01_0 - A_01_4 + A_10_2 + A_10_6);
-                                        const double tmp450 = w2*(A_02_7 - A_20_6);
-                                        const double tmp451 = w6*(A_12_6 + A_12_7 + A_21_6 + A_21_7);
-                                        const double tmp452 = w20*(A_01_7 - A_10_6);
-                                        const double tmp453 = w21*(A_01_0 - A_10_1);
-                                        const double tmp454 = w12*(A_12_0 + A_12_1 + A_21_0 + A_21_1);
-                                        const double tmp455 = w29*(A_00_0 + A_00_1);
-                                        const double tmp456 = w28*(A_00_6 + A_00_7);
-                                        const double tmp457 = w17*(-A_02_0 + A_20_1);
-                                        const double tmp458 = w21*(-A_01_7 - A_10_4);
-                                        const double tmp459 = w20*(-A_01_0 - A_10_3);
-                                        const double tmp460 = w12*(A_12_4 + A_12_5 - A_21_6 - A_21_7);
-                                        const double tmp461 = w6*(A_12_2 + A_12_3 - A_21_0 - A_21_1);
-                                        const double tmp462 = w18*(A_12_1 + A_21_7);
-                                        const double tmp463 = w4*(-A_12_6 - A_21_0);
-                                        const double tmp464 = w15*(A_02_1 + A_02_3 - A_20_5 - A_20_7);
-                                        const double tmp465 = w5*(A_02_4 + A_02_6 - A_20_0 - A_20_2);
-                                        const double tmp466 = w2*(-A_02_6 + A_20_7);
-                                        const double tmp467 = w20*(-A_01_6 + A_10_7);
-                                        const double tmp468 = w21*(-A_01_1 + A_10_0);
-                                        const double tmp469 = w17*(A_02_1 - A_20_0);
-                                        const double tmp470 = w6*(-A_12_2 - A_12_3 - A_21_4 - A_21_5);
-                                        const double tmp471 = w1*(-A_01_1 - A_01_5 - A_10_2 - A_10_6);
-                                        const double tmp472 = w15*(-A_02_4 - A_02_6 - A_20_1 - A_20_3);
-                                        const double tmp473 = w16*(-A_01_2 - A_01_6 - A_10_1 - A_10_5);
-                                        const double tmp474 = w12*(-A_12_4 - A_12_5 - A_21_2 - A_21_3);
-                                        const double tmp475 = w5*(-A_02_1 - A_02_3 - A_20_4 - A_20_6);
-                                        const double tmp476 = w18*(-A_12_6 + A_21_4);
-                                        const double tmp477 = w20*(A_01_3 - A_10_1);
-                                        const double tmp478 = w10*(A_12_0 + A_12_7 - A_21_2 - A_21_5);
-                                        const double tmp479 = w4*(A_12_1 - A_21_3);
-                                        const double tmp480 = w21*(A_01_4 - A_10_6);
-                                        const double tmp481 = w8*(-A_01_0 - A_01_7 + A_10_2 + A_10_5);
-                                        const double tmp482 = w6*(A_12_0 + A_12_1 + A_21_6 + A_21_7);
-                                        const double tmp483 = w12*(A_12_6 + A_12_7 + A_21_0 + A_21_1);
-                                        const double tmp484 = w15*(A_02_5 + A_02_7 + A_20_0 + A_20_2);
-                                        const double tmp485 = w5*(A_02_0 + A_02_2 + A_20_5 + A_20_7);
-                                        const double tmp486 = w18*(-A_12_1 + A_21_3);
-                                        const double tmp487 = w20*(A_01_4 - A_10_6);
-                                        const double tmp488 = w4*(A_12_6 - A_21_4);
-                                        const double tmp489 = w21*(A_01_3 - A_10_1);
-                                        const double tmp490 = w20*(A_01_7 - A_10_5);
-                                        const double tmp491 = w18*(A_12_2 - A_21_0);
-                                        const double tmp492 = w4*(-A_12_5 + A_21_7);
-                                        const double tmp493 = w21*(A_01_0 - A_10_2);
-                                        const double tmp494 = w20*(A_01_1 + A_10_2);
-                                        const double tmp495 = w21*(A_01_6 + A_10_5);
-                                        const double tmp496 = w18*(-A_12_2 - A_21_4);
-                                        const double tmp497 = w4*(A_12_5 + A_21_3);
-                                        const double tmp498 = w15*(-A_02_0 - A_02_2 + A_20_4 + A_20_6);
-                                        const double tmp499 = w5*(-A_02_5 - A_02_7 + A_20_1 + A_20_3);
-                                        const double tmp500 = w18*(-A_12_6 + A_21_2);
-                                        const double tmp501 = w4*(A_12_1 - A_21_5);
-                                        const double tmp502 = w17*(A_02_6 - A_20_2);
-                                        const double tmp503 = w2*(-A_02_1 + A_20_5);
-                                        const double tmp504 = w18*(-A_12_3 - A_21_5);
-                                        const double tmp505 = w4*(A_12_4 + A_21_2);
-                                        const double tmp506 = w2*(A_02_6 + A_20_3);
-                                        const double tmp507 = w17*(-A_02_1 - A_20_4);
-                                        const double tmp508 = w18*(A_12_0 + A_21_6);
-                                        const double tmp509 = w4*(-A_12_7 - A_21_1);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=tmp198 + tmp200 + tmp214 + tmp259 + tmp262 + tmp289 + tmp294 + tmp299 + tmp303 + tmp304 + tmp307 + tmp309 + tmp343 + tmp347 + tmp362 + tmp363 + tmp379 + tmp380 + tmp381 + tmp382 + tmp383 + tmp384 + tmp385 + tmp386;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp161 + tmp201 + tmp247 + tmp250 + tmp371 + tmp374 + tmp44 + tmp451 + tmp454 + tmp455 + tmp456 + tmp466 + tmp467 + tmp468 + tmp469 + tmp49 + tmp89 + tmp91 + tmp92 + tmp98;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp135 + tmp236 + tmp238 + tmp240 + tmp242 + tmp244 + tmp39 + tmp41 + tmp432 + tmp436 + tmp440 + tmp441 + tmp490 + tmp491 + tmp492 + tmp493 + tmp61 + tmp68 + tmp70 + tmp71;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp114 + tmp165 + tmp166 + tmp167 + tmp168 + tmp169 + tmp170 + tmp171 + tmp172 + tmp20 + tmp73 + tmp74 + tmp75 + tmp76 + tmp79 + tmp80;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp145 + tmp146 + tmp148 + tmp15 + tmp189 + tmp190 + tmp192 + tmp193 + tmp2 + tmp243 + tmp246 + tmp406 + tmp407 + tmp408 + tmp409 + tmp5;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp174 + tmp176 + tmp184 + tmp24 + tmp260 + tmp267 + tmp339 + tmp340 + tmp341 + tmp342 + tmp344 + tmp345 + tmp416 + tmp417 + tmp506 + tmp507;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp21 + tmp258 + tmp266 + tmp274 + tmp337 + tmp398 + tmp422 + tmp424 + tmp428 + tmp430 + tmp447 + tmp449 + tmp496 + tmp497 + tmp498 + tmp499;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113 + tmp38 + tmp87;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp145 + tmp148 + tmp161 + tmp201 + tmp202 + tmp210 + tmp371 + tmp374 + tmp440 + tmp441 + tmp450 + tmp451 + tmp452 + tmp453 + tmp454 + tmp455 + tmp456 + tmp457 + tmp89 + tmp91;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=tmp215 + tmp221 + tmp227 + tmp260 + tmp267 + tmp288 + tmp304 + tmp312 + tmp317 + tmp351 + tmp352 + tmp353 + tmp354 + tmp355 + tmp356 + tmp357 + tmp358 + tmp359 + tmp360 + tmp361 + tmp362 + tmp363 + tmp76 + tmp79;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp166 + tmp169 + tmp172 + tmp196 + tmp197 + tmp198 + tmp199 + tmp20 + tmp200 + tmp21 + tmp73 + tmp74 + tmp75 + tmp77 + tmp80 + tmp82;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp36 + tmp37 + tmp38 + tmp39 + tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp176 + tmp24 + tmp269 + tmp274 + tmp339 + tmp340 + tmp342 + tmp343 + tmp344 + tmp347 + tmp394 + tmp395 + tmp416 + tmp417 + tmp418 + tmp419;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp112 + tmp12 + tmp123 + tmp13 + tmp141 + tmp142 + tmp143 + tmp146 + tmp147 + tmp149 + tmp16 + tmp277 + tmp278 + tmp279 + tmp280 + tmp281 + tmp282 + tmp6 + tmp92 + tmp98;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp110 + tmp113 + tmp135 + tmp136 + tmp137 + tmp138 + tmp139 + tmp15 + tmp87;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp114 + tmp184 + tmp225 + tmp232 + tmp329 + tmp330 + tmp332 + tmp334 + tmp335 + tmp337 + tmp338 + tmp421 + tmp464 + tmp465 + tmp504 + tmp505;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp135 + tmp234 + tmp235 + tmp236 + tmp237 + tmp238 + tmp239 + tmp240 + tmp241 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp39 + tmp41 + tmp44 + tmp49 + tmp61 + tmp71;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp114 + tmp120 + tmp167 + tmp170 + tmp198 + tmp20 + tmp200 + tmp24 + tmp443 + tmp444 + tmp73 + tmp74 + tmp75 + tmp80 + tmp81 + tmp83;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=tmp217 + tmp231 + tmp233 + tmp258 + tmp266 + tmp271 + tmp273 + tmp288 + tmp289 + tmp290 + tmp291 + tmp292 + tmp293 + tmp294 + tmp295 + tmp296 + tmp297 + tmp298 + tmp299 + tmp300 + tmp301 + tmp302 + tmp76 + tmp79;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp101 + tmp156 + tmp157 + tmp204 + tmp205 + tmp368 + tmp371 + tmp372 + tmp374 + tmp375 + tmp377 + tmp437 + tmp438 + tmp439 + tmp440 + tmp441 + tmp442 + tmp85 + tmp87 + tmp99;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp184 + tmp21 + tmp328 + tmp337 + tmp383 + tmp386 + tmp422 + tmp423 + tmp424 + tmp427 + tmp428 + tmp430 + tmp498 + tmp499 + tmp508 + tmp509;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp104 + tmp106 + tmp108 + tmp111 + tmp113 + tmp15 + tmp160 + tmp161 + tmp162 + tmp163 + tmp164 + tmp38;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp10 + tmp112 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131 + tmp132 + tmp133 + tmp134 + tmp14 + tmp3 + tmp68 + tmp70 + tmp9;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp166 + tmp175 + tmp176 + tmp178 + tmp179 + tmp180 + tmp183 + tmp187 + tmp270 + tmp272 + tmp274 + tmp284 + tmp285 + tmp364 + tmp365 + tmp366;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp20 + tmp21 + tmp24 + tmp34 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp80 + tmp81 + tmp82 + tmp83;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp13 + tmp16 + tmp38 + tmp39 + tmp40 + tmp41 + tmp43 + tmp440 + tmp441 + tmp45 + tmp47 + tmp478 + tmp481 + tmp486 + tmp487 + tmp488 + tmp489 + tmp50 + tmp52 + tmp55;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp101 + tmp14 + tmp204 + tmp205 + tmp367 + tmp368 + tmp369 + tmp370 + tmp371 + tmp372 + tmp373 + tmp374 + tmp375 + tmp376 + tmp377 + tmp378 + tmp44 + tmp49 + tmp87 + tmp9;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=tmp179 + tmp183 + tmp198 + tmp200 + tmp214 + tmp215 + tmp216 + tmp217 + tmp218 + tmp219 + tmp220 + tmp221 + tmp222 + tmp223 + tmp224 + tmp225 + tmp226 + tmp227 + tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp135 + tmp137 + tmp139 + tmp160 + tmp161 + tmp164 + tmp471 + tmp473;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp114 + tmp274 + tmp312 + tmp317 + tmp329 + tmp332 + tmp335 + tmp337 + tmp338 + tmp399 + tmp401 + tmp446 + tmp462 + tmp463 + tmp464 + tmp465;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp166 + tmp175 + tmp176 + tmp177 + tmp178 + tmp180 + tmp181 + tmp184 + tmp187 + tmp271 + tmp273 + tmp283 + tmp284 + tmp285 + tmp286 + tmp287;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp1 + tmp10 + tmp11 + tmp12 + tmp15 + tmp152 + tmp153 + tmp154 + tmp155 + tmp156 + tmp157 + tmp158 + tmp159 + tmp17 + tmp3 + tmp4 + tmp51 + tmp54 + tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp146 + tmp15 + tmp153 + tmp154 + tmp188 + tmp189 + tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp68 + tmp70 + tmp92 + tmp98;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp166 + tmp176 + tmp184 + tmp283 + tmp339 + tmp340 + tmp341 + tmp342 + tmp343 + tmp344 + tmp345 + tmp346 + tmp347 + tmp348 + tmp349 + tmp350;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp114 + tmp274 + tmp337 + tmp383 + tmp386 + tmp422 + tmp424 + tmp426 + tmp428 + tmp429 + tmp430 + tmp445 + tmp446 + tmp447 + tmp448 + tmp449;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp104 + tmp106 + tmp107 + tmp109 + tmp112 + tmp113 + tmp135 + tmp161 + tmp482 + tmp483 + tmp484 + tmp485;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=tmp118 + tmp121 + tmp214 + tmp215 + tmp216 + tmp217 + tmp220 + tmp222 + tmp253 + tmp254 + tmp255 + tmp256 + tmp257 + tmp258 + tmp259 + tmp260 + tmp261 + tmp262 + tmp263 + tmp264 + tmp265 + tmp266 + tmp267 + tmp268;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp100 + tmp101 + tmp145 + tmp148 + tmp369 + tmp376 + tmp402 + tmp403 + tmp404 + tmp405 + tmp60 + tmp65 + tmp84 + tmp87 + tmp88 + tmp89 + tmp91 + tmp95 + tmp96 + tmp97;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp243 + tmp246 + tmp38 + tmp43 + tmp476 + tmp477 + tmp478 + tmp479 + tmp480 + tmp481 + tmp57 + tmp58 + tmp61 + tmp63 + tmp64 + tmp66 + tmp69 + tmp71 + tmp90 + tmp94;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp166 + tmp176 + tmp260 + tmp267 + tmp274 + tmp339 + tmp340 + tmp342 + tmp344 + tmp346 + tmp348 + tmp365 + tmp393 + tmp394 + tmp395 + tmp396;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp112 + tmp12 + tmp123 + tmp124 + tmp126 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147 + tmp148 + tmp149 + tmp150 + tmp151 + tmp51 + tmp54 + tmp6;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp104 + tmp106 + tmp113 + tmp136 + tmp138 + tmp15 + tmp161 + tmp38 + tmp472 + tmp475 + tmp482 + tmp483;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp184 + tmp21 + tmp312 + tmp317 + tmp327 + tmp328 + tmp329 + tmp330 + tmp331 + tmp332 + tmp333 + tmp334 + tmp335 + tmp336 + tmp337 + tmp338;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91 + tmp92 + tmp93 + tmp94 + tmp95 + tmp96 + tmp97 + tmp98 + tmp99;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=tmp217 + tmp225 + tmp232 + tmp26 + tmp265 + tmp268 + tmp288 + tmp289 + tmp29 + tmp290 + tmp293 + tmp295 + tmp308 + tmp313 + tmp343 + tmp347 + tmp358 + tmp359 + tmp410 + tmp411 + tmp412 + tmp413 + tmp414 + tmp415;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp20 + tmp22 + tmp24 + tmp25 + tmp28 + tmp30 + tmp32 + tmp35;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp13 + tmp135 + tmp16 + tmp237 + tmp238 + tmp245 + tmp319 + tmp320 + tmp321 + tmp322 + tmp323 + tmp324 + tmp325 + tmp326 + tmp45 + tmp55 + tmp57 + tmp60 + tmp64 + tmp65;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp114 + tmp184 + tmp258 + tmp266 + tmp337 + tmp420 + tmp421 + tmp422 + tmp423 + tmp424 + tmp425 + tmp426 + tmp427 + tmp428 + tmp429 + tmp430;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp104 + tmp106 + tmp113 + tmp135 + tmp15 + tmp162 + tmp163 + tmp470 + tmp474 + tmp484 + tmp485 + tmp87;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp10 + tmp112 + tmp123 + tmp125 + tmp127 + tmp128 + tmp130 + tmp131 + tmp132 + tmp156 + tmp157 + tmp243 + tmp246 + tmp278 + tmp279 + tmp3 + tmp500 + tmp501 + tmp502 + tmp503;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp175 + tmp176 + tmp178 + tmp180 + tmp182 + tmp185 + tmp187 + tmp24 + tmp269 + tmp270 + tmp271 + tmp272 + tmp273 + tmp274 + tmp275 + tmp276;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp38 + tmp42 + tmp43 + tmp53 + tmp56 + tmp57 + tmp58 + tmp59 + tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65 + tmp66 + tmp67 + tmp68 + tmp69 + tmp70 + tmp71;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp118 + tmp121 + tmp166 + tmp199 + tmp20 + tmp21 + tmp22 + tmp25 + tmp27 + tmp28 + tmp30 + tmp33 + tmp458 + tmp459 + tmp460 + tmp461;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=tmp179 + tmp183 + tmp215 + tmp255 + tmp26 + tmp261 + tmp288 + tmp29 + tmp298 + tmp300 + tmp304 + tmp316 + tmp318 + tmp351 + tmp354 + tmp355 + tmp383 + tmp386 + tmp387 + tmp388 + tmp389 + tmp390 + tmp391 + tmp392;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp100 + tmp14 + tmp161 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp208 + tmp209 + tmp210 + tmp211 + tmp212 + tmp213 + tmp88 + tmp9 + tmp90 + tmp94;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp38 + tmp470 + tmp471 + tmp472 + tmp473 + tmp474 + tmp475 + tmp87;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp21 + tmp225 + tmp232 + tmp274 + tmp329 + tmp332 + tmp333 + tmp335 + tmp336 + tmp337 + tmp338 + tmp397 + tmp398 + tmp399 + tmp400 + tmp401;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179 + tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp24;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1 + tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp114 + tmp117 + tmp119 + tmp166 + tmp171 + tmp20 + tmp22 + tmp25 + tmp26 + tmp28 + tmp29 + tmp30 + tmp460 + tmp461 + tmp494 + tmp495;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp135 + tmp238 + tmp320 + tmp324 + tmp325 + tmp326 + tmp431 + tmp432 + tmp433 + tmp434 + tmp435 + tmp436 + tmp45 + tmp51 + tmp54 + tmp55 + tmp57 + tmp64 + tmp90 + tmp94;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp100 + tmp156 + tmp157 + tmp161 + tmp201 + tmp204 + tmp205 + tmp207 + tmp208 + tmp209 + tmp211 + tmp247 + tmp248 + tmp249 + tmp250 + tmp251 + tmp252 + tmp60 + tmp65 + tmp88;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=tmp118 + tmp121 + tmp214 + tmp226 + tmp228 + tmp271 + tmp273 + tmp289 + tmp303 + tmp304 + tmp305 + tmp306 + tmp307 + tmp308 + tmp309 + tmp310 + tmp311 + tmp312 + tmp313 + tmp314 + tmp315 + tmp316 + tmp317 + tmp318;
-                                    }
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double Aw00 = 8*A_p[INDEX4(k,0,m,0, numEq,3, numComp)]*w27;
-                                        const double Aw01 = 12*A_p[INDEX4(k,0,m,1, numEq,3, numComp)]*w8;
-                                        const double Aw02 = 12*A_p[INDEX4(k,0,m,2, numEq,3, numComp)]*w11;
-                                        const double Aw10 = 12*A_p[INDEX4(k,1,m,0, numEq,3, numComp)]*w8;
-                                        const double Aw11 = 8*A_p[INDEX4(k,1,m,1, numEq,3, numComp)]*w22;
-                                        const double Aw12 = 12*A_p[INDEX4(k,1,m,2, numEq,3, numComp)]*w10;
-                                        const double Aw20 = 12*A_p[INDEX4(k,2,m,0, numEq,3, numComp)]*w11;
-                                        const double Aw21 = 12*A_p[INDEX4(k,2,m,1, numEq,3, numComp)]*w10;
-                                        const double Aw22 = 8*A_p[INDEX4(k,2,m,2, numEq,3, numComp)]*w13;
-                                        const double tmp0 = Aw01 + Aw10;
-                                        const double tmp1 = Aw01 - Aw10;
-                                        const double tmp2 = Aw02 + Aw20;
-                                        const double tmp3 = Aw02 - Aw20;
-                                        const double tmp4 = Aw12 + Aw21;
-                                        const double tmp5 = Aw12 - Aw21;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp2 - 2*tmp4;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - tmp4 + 2*tmp1 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - 2*tmp1 + tmp2 - 2*tmp5;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 - 2*tmp0 + tmp3 - tmp5;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 + 2*tmp5 + tmp0;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - 2*tmp2 + tmp1 + tmp5;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp4 - tmp1 - tmp3;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 - tmp0 - tmp2;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 - 2*tmp1 - tmp4;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 - 2*tmp2 - 2*tmp4 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 - tmp5 - tmp3;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - tmp2 - 2*tmp5 + 2*tmp1;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp2 - tmp1 + tmp5;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp5 - tmp0 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 + tmp2 + tmp0;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 + tmp1 + 2*tmp4;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 + tmp2 + 2*tmp1;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp3 + 2*tmp0 + tmp5;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp4 + 2*tmp2 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp4 - 2*tmp1 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 - 2*tmp4 - tmp3;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp4 + tmp0 - tmp2;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 - tmp0 - 2*tmp5;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 - 2*tmp2 - tmp1;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 - tmp3 + tmp5 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 - 2*tmp1 - tmp2;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 + tmp4 + 2*tmp1;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 - 2*tmp2 + 2*tmp4;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp0 + tmp2 - tmp4;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 - tmp1 - 2*tmp4;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 + tmp1 + 2*tmp2;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 - 2*tmp5 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 - 2*tmp5 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 + tmp1 + 2*tmp2;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 - tmp1 - 2*tmp4;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp0 + tmp2 - tmp4;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 - 2*tmp2 + 2*tmp4;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 + tmp4 + 2*tmp1;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 - 2*tmp1 - tmp2;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 - tmp3 + tmp5 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 - 2*tmp2 - tmp1;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 - tmp0 - 2*tmp5;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp4 + tmp0 - tmp2;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 - 2*tmp4 - tmp3;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp4 - 2*tmp1 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp4 + 2*tmp2 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp3 + 2*tmp0 + tmp5;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 + tmp2 + 2*tmp1;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 + tmp1 + 2*tmp4;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 + tmp2 + tmp0;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp5 - tmp0 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp2 - tmp1 + tmp5;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - tmp2 - 2*tmp5 + 2*tmp1;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 - tmp5 - tmp3;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 - 2*tmp2 - 2*tmp4 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 - 2*tmp1 - tmp4;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 - tmp0 - tmp2;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp4 - tmp1 - tmp3;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - 2*tmp2 + tmp1 + tmp5;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 + 2*tmp5 + tmp0;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp3 - tmp5 - 2*tmp0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - 2*tmp1 + tmp2 - 2*tmp5;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - tmp4 + 2*tmp1 + 2*tmp3;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp2 - 2*tmp4;
-                                    }
-                                }
-                            }
-                        }
-                        ///////////////
-                        // process B //
-                        ///////////////
-                        if (!B.isEmpty()) {
-                            add_EM_S=true;
-                            const double* B_p=B.getSampleDataRO(e);
-                            if (B.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double B_0_0 = B_p[INDEX4(k,0,m,0, numEq,3,numComp)];
-                                        const double B_1_0 = B_p[INDEX4(k,1,m,0, numEq,3,numComp)];
-                                        const double B_2_0 = B_p[INDEX4(k,2,m,0, numEq,3,numComp)];
-                                        const double B_0_1 = B_p[INDEX4(k,0,m,1, numEq,3,numComp)];
-                                        const double B_1_1 = B_p[INDEX4(k,1,m,1, numEq,3,numComp)];
-                                        const double B_2_1 = B_p[INDEX4(k,2,m,1, numEq,3,numComp)];
-                                        const double B_0_2 = B_p[INDEX4(k,0,m,2, numEq,3,numComp)];
-                                        const double B_1_2 = B_p[INDEX4(k,1,m,2, numEq,3,numComp)];
-                                        const double B_2_2 = B_p[INDEX4(k,2,m,2, numEq,3,numComp)];
-                                        const double B_0_3 = B_p[INDEX4(k,0,m,3, numEq,3,numComp)];
-                                        const double B_1_3 = B_p[INDEX4(k,1,m,3, numEq,3,numComp)];
-                                        const double B_2_3 = B_p[INDEX4(k,2,m,3, numEq,3,numComp)];
-                                        const double B_0_4 = B_p[INDEX4(k,0,m,4, numEq,3,numComp)];
-                                        const double B_1_4 = B_p[INDEX4(k,1,m,4, numEq,3,numComp)];
-                                        const double B_2_4 = B_p[INDEX4(k,2,m,4, numEq,3,numComp)];
-                                        const double B_0_5 = B_p[INDEX4(k,0,m,5, numEq,3,numComp)];
-                                        const double B_1_5 = B_p[INDEX4(k,1,m,5, numEq,3,numComp)];
-                                        const double B_2_5 = B_p[INDEX4(k,2,m,5, numEq,3,numComp)];
-                                        const double B_0_6 = B_p[INDEX4(k,0,m,6, numEq,3,numComp)];
-                                        const double B_1_6 = B_p[INDEX4(k,1,m,6, numEq,3,numComp)];
-                                        const double B_2_6 = B_p[INDEX4(k,2,m,6, numEq,3,numComp)];
-                                        const double B_0_7 = B_p[INDEX4(k,0,m,7, numEq,3,numComp)];
-                                        const double B_1_7 = B_p[INDEX4(k,1,m,7, numEq,3,numComp)];
-                                        const double B_2_7 = B_p[INDEX4(k,2,m,7, numEq,3,numComp)];
-                                        const double tmp0 = w38*(B_2_1 + B_2_2);
-                                        const double tmp1 = w42*(B_1_3 + B_1_7);
-                                        const double tmp2 = w41*(B_0_3 + B_0_7);
-                                        const double tmp3 = w37*(B_1_1 + B_1_5);
-                                        const double tmp4 = w39*(B_0_2 + B_0_6);
-                                        const double tmp5 = w45*(B_2_5 + B_2_6);
-                                        const double tmp6 = w36*(B_0_1 + B_0_5);
-                                        const double tmp7 = w40*(B_1_2 + B_1_6);
-                                        const double tmp8 = w33*(B_0_0 + B_0_4);
-                                        const double tmp9 = w34*(B_1_0 + B_1_4);
-                                        const double tmp10 = w38*(B_2_4 + B_2_5 + B_2_6 + B_2_7);
-                                        const double tmp11 = w42*(-B_1_6 - B_1_7);
-                                        const double tmp12 = w41*(-B_0_5 - B_0_7);
-                                        const double tmp13 = w37*(-B_1_4 - B_1_5);
-                                        const double tmp14 = w39*(-B_0_4 - B_0_6);
-                                        const double tmp15 = w45*(B_2_0 + B_2_1 + B_2_2 + B_2_3);
-                                        const double tmp16 = w36*(-B_0_1 - B_0_3);
-                                        const double tmp17 = w40*(-B_1_2 - B_1_3);
-                                        const double tmp18 = w33*(-B_0_0 - B_0_2);
-                                        const double tmp19 = w34*(-B_1_0 - B_1_1);
-                                        const double tmp20 = w38*(-B_2_5 - B_2_7);
-                                        const double tmp21 = w35*(-B_2_4 - B_2_6);
-                                        const double tmp22 = w41*(B_0_1 + B_0_3);
-                                        const double tmp23 = w37*(-B_1_2 - B_1_7);
-                                        const double tmp24 = w39*(B_0_0 + B_0_2);
-                                        const double tmp25 = w45*(-B_2_0 - B_2_2);
-                                        const double tmp26 = w36*(B_0_5 + B_0_7);
-                                        const double tmp27 = w40*(-B_1_0 - B_1_5);
-                                        const double tmp28 = w33*(B_0_4 + B_0_6);
-                                        const double tmp29 = w46*(-B_2_1 - B_2_3);
-                                        const double tmp30 = w38*(B_2_0 + B_2_2);
-                                        const double tmp31 = w35*(B_2_1 + B_2_3);
-                                        const double tmp32 = w41*(-B_0_4 - B_0_6);
-                                        const double tmp33 = w37*(B_1_0 + B_1_5);
-                                        const double tmp34 = w39*(-B_0_5 - B_0_7);
-                                        const double tmp35 = w45*(B_2_5 + B_2_7);
-                                        const double tmp36 = w36*(-B_0_0 - B_0_2);
-                                        const double tmp37 = w40*(B_1_2 + B_1_7);
-                                        const double tmp38 = w33*(-B_0_1 - B_0_3);
-                                        const double tmp39 = w46*(B_2_4 + B_2_6);
-                                        const double tmp40 = w38*(-B_2_0 - B_2_1 - B_2_2 - B_2_3);
-                                        const double tmp41 = w42*(B_1_0 + B_1_1);
-                                        const double tmp42 = w41*(B_0_0 + B_0_2);
-                                        const double tmp43 = w37*(B_1_2 + B_1_3);
-                                        const double tmp44 = w39*(B_0_1 + B_0_3);
-                                        const double tmp45 = w45*(-B_2_4 - B_2_5 - B_2_6 - B_2_7);
-                                        const double tmp46 = w36*(B_0_4 + B_0_6);
-                                        const double tmp47 = w40*(B_1_4 + B_1_5);
-                                        const double tmp48 = w33*(B_0_5 + B_0_7);
-                                        const double tmp49 = w34*(B_1_6 + B_1_7);
-                                        const double tmp50 = w38*(B_2_0 + B_2_1);
-                                        const double tmp51 = w42*(-B_1_4 - B_1_5);
-                                        const double tmp52 = w35*(B_2_2 + B_2_3);
-                                        const double tmp53 = w37*(-B_1_6 - B_1_7);
-                                        const double tmp54 = w39*(B_0_0 + B_0_6);
-                                        const double tmp55 = w45*(B_2_6 + B_2_7);
-                                        const double tmp56 = w36*(B_0_1 + B_0_7);
-                                        const double tmp57 = w40*(-B_1_0 - B_1_1);
-                                        const double tmp58 = w46*(B_2_4 + B_2_5);
-                                        const double tmp59 = w34*(-B_1_2 - B_1_3);
-                                        const double tmp60 = w38*(-B_2_4 - B_2_5 - B_2_6 - B_2_7);
-                                        const double tmp61 = w37*(-B_1_2 - B_1_3 - B_1_6 - B_1_7);
-                                        const double tmp62 = w39*(-B_0_1 - B_0_3 - B_0_5 - B_0_7);
-                                        const double tmp63 = w45*(-B_2_0 - B_2_1 - B_2_2 - B_2_3);
-                                        const double tmp64 = w36*(-B_0_0 - B_0_2 - B_0_4 - B_0_6);
-                                        const double tmp65 = w40*(-B_1_0 - B_1_1 - B_1_4 - B_1_5);
-                                        const double tmp66 = w41*(B_0_4 + B_0_6);
-                                        const double tmp67 = w39*(B_0_5 + B_0_7);
-                                        const double tmp68 = w36*(B_0_0 + B_0_2);
-                                        const double tmp69 = w33*(B_0_1 + B_0_3);
-                                        const double tmp70 = w38*(-B_2_4 - B_2_7);
-                                        const double tmp71 = w42*(B_1_2 + B_1_6);
-                                        const double tmp72 = w41*(-B_0_2 - B_0_6);
-                                        const double tmp73 = w37*(B_1_0 + B_1_4);
-                                        const double tmp74 = w39*(-B_0_3 - B_0_7);
-                                        const double tmp75 = w45*(-B_2_0 - B_2_3);
-                                        const double tmp76 = w36*(-B_0_0 - B_0_4);
-                                        const double tmp77 = w40*(B_1_3 + B_1_7);
-                                        const double tmp78 = w33*(-B_0_1 - B_0_5);
-                                        const double tmp79 = w34*(B_1_1 + B_1_5);
-                                        const double tmp80 = w39*(B_0_0 + B_0_2 + B_0_4 + B_0_6);
-                                        const double tmp81 = w36*(B_0_1 + B_0_3 + B_0_5 + B_0_7);
-                                        const double tmp82 = w38*(B_2_0 + B_2_3);
-                                        const double tmp83 = w42*(-B_1_1 - B_1_5);
-                                        const double tmp84 = w41*(B_0_1 + B_0_5);
-                                        const double tmp85 = w37*(-B_1_3 - B_1_7);
-                                        const double tmp86 = w39*(B_0_0 + B_0_4);
-                                        const double tmp87 = w45*(B_2_4 + B_2_7);
-                                        const double tmp88 = w36*(B_0_3 + B_0_7);
-                                        const double tmp89 = w40*(-B_1_0 - B_1_4);
-                                        const double tmp90 = w33*(B_0_2 + B_0_6);
-                                        const double tmp91 = w34*(-B_1_2 - B_1_6);
-                                        const double tmp92 = w38*(-B_2_5 - B_2_6);
-                                        const double tmp93 = w45*(-B_2_1 - B_2_2);
-                                        const double tmp94 = w37*(B_1_0 + B_1_1 + B_1_4 + B_1_5);
-                                        const double tmp95 = w40*(B_1_2 + B_1_3 + B_1_6 + B_1_7);
-                                        const double tmp96 = w42*(-B_1_2 - B_1_3);
-                                        const double tmp97 = w41*(-B_0_1 - B_0_3);
-                                        const double tmp98 = w37*(-B_1_0 - B_1_1);
-                                        const double tmp99 = w39*(-B_0_0 - B_0_2);
-                                        const double tmp100 = w36*(-B_0_5 - B_0_7);
-                                        const double tmp101 = w40*(-B_1_6 - B_1_7);
-                                        const double tmp102 = w33*(-B_0_4 - B_0_6);
-                                        const double tmp103 = w34*(-B_1_4 - B_1_5);
-                                        const double tmp104 = w38*(B_2_6 + B_2_7);
-                                        const double tmp105 = w35*(B_2_4 + B_2_5);
-                                        const double tmp106 = w41*(B_0_2 + B_0_6);
-                                        const double tmp107 = w37*(B_1_2 + B_1_3 + B_1_6 + B_1_7);
-                                        const double tmp108 = w39*(B_0_3 + B_0_7);
-                                        const double tmp109 = w45*(B_2_0 + B_2_1);
-                                        const double tmp110 = w36*(B_0_0 + B_0_4);
-                                        const double tmp111 = w40*(B_1_0 + B_1_1 + B_1_4 + B_1_5);
-                                        const double tmp112 = w33*(B_0_1 + B_0_5);
-                                        const double tmp113 = w46*(B_2_2 + B_2_3);
-                                        const double tmp114 = w42*(-B_1_0 - B_1_4);
-                                        const double tmp115 = w41*(-B_0_0 - B_0_4);
-                                        const double tmp116 = w37*(-B_1_2 - B_1_6);
-                                        const double tmp117 = w39*(-B_0_1 - B_0_5);
-                                        const double tmp118 = w36*(-B_0_2 - B_0_6);
-                                        const double tmp119 = w40*(-B_1_1 - B_1_5);
-                                        const double tmp120 = w33*(-B_0_3 - B_0_7);
-                                        const double tmp121 = w34*(-B_1_3 - B_1_7);
-                                        const double tmp122 = w38*(B_2_2 + B_2_3);
-                                        const double tmp123 = w42*(B_1_6 + B_1_7);
-                                        const double tmp124 = w35*(B_2_0 + B_2_1);
-                                        const double tmp125 = w37*(B_1_4 + B_1_5);
-                                        const double tmp126 = w39*(-B_0_3 - B_0_5);
-                                        const double tmp127 = w45*(B_2_4 + B_2_5);
-                                        const double tmp128 = w36*(-B_0_2 - B_0_4);
-                                        const double tmp129 = w40*(B_1_2 + B_1_3);
-                                        const double tmp130 = w46*(B_2_6 + B_2_7);
-                                        const double tmp131 = w34*(B_1_0 + B_1_1);
-                                        const double tmp132 = w38*(-B_2_1 - B_2_2);
-                                        const double tmp133 = w37*(B_1_2 + B_1_7);
-                                        const double tmp134 = w39*(B_0_1 + B_0_7);
-                                        const double tmp135 = w36*(B_0_0 + B_0_6);
-                                        const double tmp136 = w40*(B_1_0 + B_1_5);
-                                        const double tmp137 = w45*(-B_2_5 - B_2_6);
-                                        const double tmp138 = w38*(-B_2_4 - B_2_6);
-                                        const double tmp139 = w35*(-B_2_5 - B_2_7);
-                                        const double tmp140 = w41*(-B_0_0 - B_0_2);
-                                        const double tmp141 = w37*(B_1_1 + B_1_4);
-                                        const double tmp142 = w39*(-B_0_1 - B_0_3);
-                                        const double tmp143 = w45*(-B_2_1 - B_2_3);
-                                        const double tmp144 = w36*(-B_0_4 - B_0_6);
-                                        const double tmp145 = w40*(B_1_3 + B_1_6);
-                                        const double tmp146 = w33*(-B_0_5 - B_0_7);
-                                        const double tmp147 = w46*(-B_2_0 - B_2_2);
-                                        const double tmp148 = w39*(B_0_2 + B_0_4);
-                                        const double tmp149 = w36*(B_0_3 + B_0_5);
-                                        const double tmp150 = w38*(B_2_5 + B_2_6);
-                                        const double tmp151 = w37*(-B_1_0 - B_1_5);
-                                        const double tmp152 = w39*(-B_0_0 - B_0_6);
-                                        const double tmp153 = w45*(B_2_1 + B_2_2);
-                                        const double tmp154 = w36*(-B_0_1 - B_0_7);
-                                        const double tmp155 = w40*(-B_1_2 - B_1_7);
-                                        const double tmp156 = w41*(-B_0_3 - B_0_7);
-                                        const double tmp157 = w39*(-B_0_2 - B_0_6);
-                                        const double tmp158 = w36*(-B_0_1 - B_0_5);
-                                        const double tmp159 = w33*(-B_0_0 - B_0_4);
-                                        const double tmp160 = w38*(-B_2_2 - B_2_3);
-                                        const double tmp161 = w35*(-B_2_0 - B_2_1);
-                                        const double tmp162 = w45*(-B_2_4 - B_2_5);
-                                        const double tmp163 = w46*(-B_2_6 - B_2_7);
-                                        const double tmp164 = w38*(-B_2_0 - B_2_3);
-                                        const double tmp165 = w37*(B_1_3 + B_1_6);
-                                        const double tmp166 = w40*(B_1_1 + B_1_4);
-                                        const double tmp167 = w45*(-B_2_4 - B_2_7);
-                                        const double tmp168 = w39*(B_0_3 + B_0_5);
-                                        const double tmp169 = w36*(B_0_2 + B_0_4);
-                                        const double tmp170 = w38*(B_2_1 + B_2_3);
-                                        const double tmp171 = w35*(B_2_0 + B_2_2);
-                                        const double tmp172 = w41*(B_0_5 + B_0_7);
-                                        const double tmp173 = w37*(-B_1_3 - B_1_6);
-                                        const double tmp174 = w39*(B_0_4 + B_0_6);
-                                        const double tmp175 = w45*(B_2_4 + B_2_6);
-                                        const double tmp176 = w36*(B_0_1 + B_0_3);
-                                        const double tmp177 = w40*(-B_1_1 - B_1_4);
-                                        const double tmp178 = w33*(B_0_0 + B_0_2);
-                                        const double tmp179 = w46*(B_2_5 + B_2_7);
-                                        const double tmp180 = w38*(B_2_5 + B_2_7);
-                                        const double tmp181 = w42*(-B_1_3 - B_1_7);
-                                        const double tmp182 = w35*(B_2_4 + B_2_6);
-                                        const double tmp183 = w37*(-B_1_1 - B_1_5);
-                                        const double tmp184 = w39*(B_0_1 + B_0_3 + B_0_5 + B_0_7);
-                                        const double tmp185 = w45*(B_2_0 + B_2_2);
-                                        const double tmp186 = w36*(B_0_0 + B_0_2 + B_0_4 + B_0_6);
-                                        const double tmp187 = w40*(-B_1_2 - B_1_6);
-                                        const double tmp188 = w46*(B_2_1 + B_2_3);
-                                        const double tmp189 = w34*(-B_1_0 - B_1_4);
-                                        const double tmp190 = w38*(B_2_4 + B_2_5);
-                                        const double tmp191 = w35*(B_2_6 + B_2_7);
-                                        const double tmp192 = w41*(-B_0_1 - B_0_5);
-                                        const double tmp193 = w37*(-B_1_0 - B_1_1 - B_1_4 - B_1_5);
-                                        const double tmp194 = w39*(-B_0_0 - B_0_4);
-                                        const double tmp195 = w45*(B_2_2 + B_2_3);
-                                        const double tmp196 = w36*(-B_0_3 - B_0_7);
-                                        const double tmp197 = w40*(-B_1_2 - B_1_3 - B_1_6 - B_1_7);
-                                        const double tmp198 = w33*(-B_0_2 - B_0_6);
-                                        const double tmp199 = w46*(B_2_0 + B_2_1);
-                                        const double tmp200 = w38*(-B_2_6 - B_2_7);
-                                        const double tmp201 = w42*(B_1_2 + B_1_3);
-                                        const double tmp202 = w35*(-B_2_4 - B_2_5);
-                                        const double tmp203 = w37*(B_1_0 + B_1_1);
-                                        const double tmp204 = w45*(-B_2_0 - B_2_1);
-                                        const double tmp205 = w40*(B_1_6 + B_1_7);
-                                        const double tmp206 = w46*(-B_2_2 - B_2_3);
-                                        const double tmp207 = w34*(B_1_4 + B_1_5);
-                                        const double tmp208 = w37*(-B_1_1 - B_1_4);
-                                        const double tmp209 = w39*(-B_0_2 - B_0_4);
-                                        const double tmp210 = w36*(-B_0_3 - B_0_5);
-                                        const double tmp211 = w40*(-B_1_3 - B_1_6);
-                                        const double tmp212 = w38*(B_2_4 + B_2_7);
-                                        const double tmp213 = w45*(B_2_0 + B_2_3);
-                                        const double tmp214 = w41*(B_0_0 + B_0_4);
-                                        const double tmp215 = w39*(B_0_1 + B_0_5);
-                                        const double tmp216 = w36*(B_0_2 + B_0_6);
-                                        const double tmp217 = w33*(B_0_3 + B_0_7);
-                                        const double tmp218 = w42*(B_1_1 + B_1_5);
-                                        const double tmp219 = w37*(B_1_3 + B_1_7);
-                                        const double tmp220 = w40*(B_1_0 + B_1_4);
-                                        const double tmp221 = w34*(B_1_2 + B_1_6);
-                                        const double tmp222 = w39*(-B_0_1 - B_0_7);
-                                        const double tmp223 = w36*(-B_0_0 - B_0_6);
-                                        const double tmp224 = w38*(-B_2_0 - B_2_1);
-                                        const double tmp225 = w35*(-B_2_2 - B_2_3);
-                                        const double tmp226 = w45*(-B_2_6 - B_2_7);
-                                        const double tmp227 = w46*(-B_2_4 - B_2_5);
-                                        const double tmp228 = w38*(B_2_4 + B_2_6);
-                                        const double tmp229 = w42*(B_1_0 + B_1_4);
-                                        const double tmp230 = w35*(B_2_5 + B_2_7);
-                                        const double tmp231 = w37*(B_1_2 + B_1_6);
-                                        const double tmp232 = w39*(-B_0_0 - B_0_2 - B_0_4 - B_0_6);
-                                        const double tmp233 = w45*(B_2_1 + B_2_3);
-                                        const double tmp234 = w36*(-B_0_1 - B_0_3 - B_0_5 - B_0_7);
-                                        const double tmp235 = w40*(B_1_1 + B_1_5);
-                                        const double tmp236 = w46*(B_2_0 + B_2_2);
-                                        const double tmp237 = w34*(B_1_3 + B_1_7);
-                                        const double tmp238 = w42*(-B_1_2 - B_1_6);
-                                        const double tmp239 = w37*(-B_1_0 - B_1_4);
-                                        const double tmp240 = w40*(-B_1_3 - B_1_7);
-                                        const double tmp241 = w34*(-B_1_1 - B_1_5);
-                                        const double tmp242 = w38*(-B_2_4 - B_2_5);
-                                        const double tmp243 = w42*(-B_1_0 - B_1_1);
-                                        const double tmp244 = w35*(-B_2_6 - B_2_7);
-                                        const double tmp245 = w37*(-B_1_2 - B_1_3);
-                                        const double tmp246 = w45*(-B_2_2 - B_2_3);
-                                        const double tmp247 = w40*(-B_1_4 - B_1_5);
-                                        const double tmp248 = w46*(-B_2_0 - B_2_1);
-                                        const double tmp249 = w34*(-B_1_6 - B_1_7);
-                                        const double tmp250 = w42*(B_1_4 + B_1_5);
-                                        const double tmp251 = w37*(B_1_6 + B_1_7);
-                                        const double tmp252 = w40*(B_1_0 + B_1_1);
-                                        const double tmp253 = w34*(B_1_2 + B_1_3);
-                                        const double tmp254 = w38*(-B_2_1 - B_2_3);
-                                        const double tmp255 = w35*(-B_2_0 - B_2_2);
-                                        const double tmp256 = w45*(-B_2_4 - B_2_6);
-                                        const double tmp257 = w46*(-B_2_5 - B_2_7);
-                                        const double tmp258 = w38*(B_2_0 + B_2_1 + B_2_2 + B_2_3);
-                                        const double tmp259 = w45*(B_2_4 + B_2_5 + B_2_6 + B_2_7);
-                                        const double tmp260 = w38*(-B_2_0 - B_2_2);
-                                        const double tmp261 = w35*(-B_2_1 - B_2_3);
-                                        const double tmp262 = w45*(-B_2_5 - B_2_7);
-                                        const double tmp263 = w46*(-B_2_4 - B_2_6);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-B_0_0*w50 - B_0_1*w41 - B_0_6*w33 - B_0_7*w49 + B_1_0*w47 - B_1_2*w42 - B_1_5*w34 + B_1_7*w48 - B_2_0*w43 - B_2_3*w35 - B_2_4*w46 - B_2_7*w44 + tmp132 + tmp137 + tmp208 + tmp209 + tmp210 + tmp211;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-B_0_0*w41 - B_0_1*w50 - B_0_6*w49 - B_0_7*w33 + tmp126 + tmp128 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-B_1_0*w42 + B_1_2*w47 + B_1_5*w48 - B_1_7*w34 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp146 + tmp147 + tmp173 + tmp177;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp40 + tmp45 + tmp96 + tmp97 + tmp98 + tmp99;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-B_2_0*w46 - B_2_3*w44 - B_2_4*w43 - B_2_7*w35 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp192 + tmp193 + tmp194 + tmp196 + tmp197 + tmp198 + tmp224 + tmp225 + tmp226 + tmp227;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp232 + tmp234 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=B_0_0*w50 + B_0_1*w41 + B_0_6*w33 + B_0_7*w49 + tmp148 + tmp149 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=B_0_0*w41 + B_0_1*w50 + B_0_6*w49 + B_0_7*w33 + B_1_1*w47 - B_1_3*w42 - B_1_4*w34 + B_1_6*w48 - B_2_1*w43 - B_2_2*w35 - B_2_5*w46 - B_2_6*w44 + tmp151 + tmp155 + tmp164 + tmp167 + tmp168 + tmp169;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp101 + tmp103 + tmp40 + tmp42 + tmp44 + tmp45 + tmp46 + tmp48 + tmp96 + tmp98;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-B_1_1*w42 + B_1_3*w47 + B_1_4*w48 - B_1_6*w34 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp193 + tmp197 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-B_2_1*w46 - B_2_2*w44 - B_2_5*w43 - B_2_6*w35 + tmp70 + tmp75 + tmp83 + tmp84 + tmp85 + tmp86 + tmp88 + tmp89 + tmp90 + tmp91;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp60 + tmp61 + tmp63 + tmp65 + tmp80 + tmp81;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp181 + tmp183 + tmp184 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-B_1_0*w47 + B_1_2*w42 + B_1_5*w34 - B_1_7*w48 + tmp138 + tmp139 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp100 + tmp102 + tmp40 + tmp41 + tmp43 + tmp45 + tmp47 + tmp49 + tmp97 + tmp99;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-B_0_2*w50 - B_0_3*w41 - B_0_4*w33 - B_0_5*w49 + B_1_0*w42 - B_1_2*w47 - B_1_5*w48 + B_1_7*w34 - B_2_1*w35 - B_2_2*w43 - B_2_5*w44 - B_2_6*w46 + tmp152 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-B_0_2*w41 - B_0_3*w50 - B_0_4*w49 - B_0_5*w33 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp229 + tmp231 + tmp232 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp60 + tmp62 + tmp63 + tmp64 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-B_2_1*w44 - B_2_2*w46 - B_2_5*w35 - B_2_6*w43 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp107 + tmp111 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-B_1_1*w47 + B_1_3*w42 + B_1_4*w34 - B_1_6*w48 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp28 + tmp29 + tmp33 + tmp37;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=B_0_2*w50 + B_0_3*w41 + B_0_4*w33 + B_0_5*w49 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp54 + tmp56;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=B_0_2*w41 + B_0_3*w50 + B_0_4*w49 + B_0_5*w33 + B_1_1*w42 - B_1_3*w47 - B_1_4*w48 + B_1_6*w34 - B_2_0*w35 - B_2_3*w43 - B_2_4*w44 - B_2_7*w46 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp60 + tmp63 + tmp80 + tmp81 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp184 + tmp186 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp106 + tmp107 + tmp108 + tmp110 + tmp111 + tmp112 + tmp160 + tmp161 + tmp162 + tmp163;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-B_2_0*w44 - B_2_3*w46 - B_2_4*w35 - B_2_7*w43 + tmp1 + tmp2 + tmp3 + tmp4 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=B_2_0*w43 + B_2_3*w35 + B_2_4*w46 + B_2_7*w44 + tmp0 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp5;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp228 + tmp230 + tmp232 + tmp233 + tmp234 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp62 + tmp64 + tmp65;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-B_0_2*w33 - B_0_3*w49 - B_0_4*w50 - B_0_5*w41 - B_1_1*w34 + B_1_3*w48 + B_1_4*w47 - B_1_6*w42 + B_2_0*w46 + B_2_3*w44 + B_2_4*w43 + B_2_7*w35 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-B_0_2*w49 - B_0_3*w33 - B_0_4*w41 - B_0_5*w50 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp55 + tmp57 + tmp58 + tmp59;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=B_1_1*w48 - B_1_3*w34 - B_1_4*w42 + B_1_6*w47 + tmp23 + tmp27 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp38 + tmp39;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp190 + tmp191 + tmp193 + tmp195 + tmp197 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=B_2_1*w43 + B_2_2*w35 + B_2_5*w46 + B_2_6*w44 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp65 + tmp80 + tmp81;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=B_0_2*w33 + B_0_3*w49 + B_0_4*w50 + B_0_5*w41 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=B_0_2*w49 + B_0_3*w33 + B_0_4*w41 + B_0_5*w50 - B_1_0*w34 + B_1_2*w48 + B_1_5*w47 - B_1_7*w42 + B_2_1*w46 + B_2_2*w44 + B_2_5*w43 + B_2_6*w35 + tmp134 + tmp135 + tmp208 + tmp211 + tmp212 + tmp213;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp10 + tmp11 + tmp13 + tmp15 + tmp17 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=B_1_0*w48 - B_1_2*w34 - B_1_5*w42 + B_1_7*w47 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233 + tmp234 + tmp235 + tmp236 + tmp237;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp258 + tmp259 + tmp62 + tmp64 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=B_2_1*w35 + B_2_2*w43 + B_2_5*w44 + B_2_6*w46 + tmp71 + tmp72 + tmp73 + tmp74 + tmp76 + tmp77 + tmp78 + tmp79 + tmp82 + tmp87;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp104 + tmp105 + tmp107 + tmp109 + tmp111 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=B_1_1*w34 - B_1_3*w48 - B_1_4*w47 + B_1_6*w42 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp10 + tmp12 + tmp14 + tmp15 + tmp16 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-B_0_0*w33 - B_0_1*w49 - B_0_6*w50 - B_0_7*w41 - B_1_1*w48 + B_1_3*w34 + B_1_4*w42 - B_1_6*w47 + B_2_1*w44 + B_2_2*w46 + B_2_5*w35 + B_2_6*w43 + tmp133 + tmp136 + tmp209 + tmp210 + tmp212 + tmp213;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-B_0_0*w49 - B_0_1*w33 - B_0_6*w41 - B_0_7*w50 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp258 + tmp259 + tmp80 + tmp81 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp180 + tmp182 + tmp184 + tmp185 + tmp186 + tmp188 + tmp218 + tmp219 + tmp220 + tmp221;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=B_2_0*w35 + B_2_3*w43 + B_2_4*w44 + B_2_7*w46 + tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp10 + tmp15 + tmp250 + tmp251 + tmp252 + tmp253 + tmp66 + tmp67 + tmp68 + tmp69;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=B_1_0*w34 - B_1_2*w48 - B_1_5*w47 + B_1_7*w42 + tmp141 + tmp145 + tmp170 + tmp171 + tmp172 + tmp174 + tmp175 + tmp176 + tmp178 + tmp179;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=B_0_0*w33 + B_0_1*w49 + B_0_6*w50 + B_0_7*w41 + tmp122 + tmp123 + tmp124 + tmp125 + tmp127 + tmp129 + tmp130 + tmp131 + tmp148 + tmp149;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=B_0_0*w49 + B_0_1*w33 + B_0_6*w41 + B_0_7*w50 - B_1_0*w48 + B_1_2*w34 + B_1_5*w42 - B_1_7*w47 + B_2_0*w44 + B_2_3*w46 + B_2_4*w35 + B_2_7*w43 + tmp150 + tmp153 + tmp165 + tmp166 + tmp168 + tmp169;
-                                    }
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double wB0 = B_p[INDEX3(k,0,m,numEq,3)]*w55;
-                                        const double wB1 = B_p[INDEX3(k,1,m,numEq,3)]*w56;
-                                        const double wB2 = B_p[INDEX3(k,2,m,numEq,3)]*w54;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+= 4*wB0 + 4*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+= 4*wB0 + 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+= 2*wB0 + 4*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+= 2*wB0 + 2*wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+= 2*wB0 + 2*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+= 2*wB0 +   wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=   wB0 + 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=   wB0 +   wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-4*wB0 + 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=-4*wB0 + 4*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=-2*wB0 + 2*wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-2*wB0 + 4*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=-2*wB0 +   wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-2*wB0 + 2*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=  -wB0 +   wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  -wB0 + 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+= 2*wB0 - 4*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+= 2*wB0 - 2*wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+= 4*wB0 - 4*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+= 4*wB0 - 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=   wB0 - 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=   wB0 -   wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+= 2*wB0 - 2*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+= 2*wB0 -   wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=-2*wB0 - 2*wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-2*wB0 - 4*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-4*wB0 - 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=-4*wB0 - 4*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=  -wB0 -   wB1 +   wB2;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  -wB0 - 2*wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=-2*wB0 -   wB1 + 2*wB2;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-2*wB0 - 2*wB1 + 4*wB2;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+= 2*wB0 + 2*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+= 2*wB0 +   wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=   wB0 + 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=   wB0 +   wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+= 4*wB0 + 4*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+= 4*wB0 + 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+= 2*wB0 + 4*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+= 2*wB0 + 2*wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=-2*wB0 +   wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-2*wB0 + 2*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=  -wB0 +   wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  -wB0 + 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-4*wB0 + 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=-4*wB0 + 4*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=-2*wB0 + 2*wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=-2*wB0 + 4*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=   wB0 - 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=   wB0 -   wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+= 2*wB0 - 2*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+= 2*wB0 -   wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+= 2*wB0 - 4*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+= 2*wB0 - 2*wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+= 4*wB0 - 4*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+= 4*wB0 - 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=  -wB0 -   wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  -wB0 - 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=-2*wB0 -   wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-2*wB0 - 2*wB1 - 4*wB2;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=-2*wB0 - 2*wB1 -   wB2;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=-2*wB0 - 4*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-4*wB0 - 2*wB1 - 2*wB2;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=-4*wB0 - 4*wB1 - 4*wB2;
-                                    }
-                                }
-                            }
-                        }
-                        ///////////////
-                        // process C //
-                        ///////////////
-                        if (!C.isEmpty()) {
-                            add_EM_S=true;
-                            const double* C_p=C.getSampleDataRO(e);
-                            if (C.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double C_0_0 = C_p[INDEX4(k,m,0, 0, numEq,numComp,3)];
-                                        const double C_1_0 = C_p[INDEX4(k,m,1, 0, numEq,numComp,3)];
-                                        const double C_2_0 = C_p[INDEX4(k,m,2, 0, numEq,numComp,3)];
-                                        const double C_0_1 = C_p[INDEX4(k,m,0, 1, numEq,numComp,3)];
-                                        const double C_1_1 = C_p[INDEX4(k,m,1, 1, numEq,numComp,3)];
-                                        const double C_2_1 = C_p[INDEX4(k,m,2, 1, numEq,numComp,3)];
-                                        const double C_0_2 = C_p[INDEX4(k,m,0, 2, numEq,numComp,3)];
-                                        const double C_1_2 = C_p[INDEX4(k,m,1, 2, numEq,numComp,3)];
-                                        const double C_2_2 = C_p[INDEX4(k,m,2, 2, numEq,numComp,3)];
-                                        const double C_0_3 = C_p[INDEX4(k,m,0, 3, numEq,numComp,3)];
-                                        const double C_1_3 = C_p[INDEX4(k,m,1, 3, numEq,numComp,3)];
-                                        const double C_2_3 = C_p[INDEX4(k,m,2, 3, numEq,numComp,3)];
-                                        const double C_0_4 = C_p[INDEX4(k,m,0, 4, numEq,numComp,3)];
-                                        const double C_1_4 = C_p[INDEX4(k,m,1, 4, numEq,numComp,3)];
-                                        const double C_2_4 = C_p[INDEX4(k,m,2, 4, numEq,numComp,3)];
-                                        const double C_0_5 = C_p[INDEX4(k,m,0, 5, numEq,numComp,3)];
-                                        const double C_1_5 = C_p[INDEX4(k,m,1, 5, numEq,numComp,3)];
-                                        const double C_2_5 = C_p[INDEX4(k,m,2, 5, numEq,numComp,3)];
-                                        const double C_0_6 = C_p[INDEX4(k,m,0, 6, numEq,numComp,3)];
-                                        const double C_1_6 = C_p[INDEX4(k,m,1, 6, numEq,numComp,3)];
-                                        const double C_2_6 = C_p[INDEX4(k,m,2, 6, numEq,numComp,3)];
-                                        const double C_0_7 = C_p[INDEX4(k,m,0, 7, numEq,numComp,3)];
-                                        const double C_1_7 = C_p[INDEX4(k,m,1, 7, numEq,numComp,3)];
-                                        const double C_2_7 = C_p[INDEX4(k,m,2, 7, numEq,numComp,3)];
-                                        const double tmp0 = w38*(-C_2_5 - C_2_6);
-                                        const double tmp1 = w42*(C_1_3 + C_1_7);
-                                        const double tmp2 = w41*(C_0_3 + C_0_7);
-                                        const double tmp3 = w37*(C_1_1 + C_1_5);
-                                        const double tmp4 = w39*(C_0_2 + C_0_6);
-                                        const double tmp5 = w45*(-C_2_1 - C_2_2);
-                                        const double tmp6 = w36*(C_0_1 + C_0_5);
-                                        const double tmp7 = w40*(C_1_2 + C_1_6);
-                                        const double tmp8 = w33*(C_0_0 + C_0_4);
-                                        const double tmp9 = w34*(C_1_0 + C_1_4);
-                                        const double tmp10 = w38*(C_2_4 + C_2_5 + C_2_6 + C_2_7);
-                                        const double tmp11 = w42*(C_1_4 + C_1_5);
-                                        const double tmp12 = w41*(C_0_4 + C_0_6);
-                                        const double tmp13 = w37*(C_1_6 + C_1_7);
-                                        const double tmp14 = w39*(C_0_5 + C_0_7);
-                                        const double tmp15 = w45*(C_2_0 + C_2_1 + C_2_2 + C_2_3);
-                                        const double tmp16 = w36*(C_0_0 + C_0_2);
-                                        const double tmp17 = w40*(C_1_0 + C_1_1);
-                                        const double tmp18 = w33*(C_0_1 + C_0_3);
-                                        const double tmp19 = w34*(C_1_2 + C_1_3);
-                                        const double tmp20 = w38*(-C_2_5 - C_2_7);
-                                        const double tmp21 = w35*(-C_2_4 - C_2_6);
-                                        const double tmp22 = w41*(C_0_1 + C_0_3);
-                                        const double tmp23 = w37*(C_1_0 + C_1_5);
-                                        const double tmp24 = w39*(C_0_0 + C_0_2);
-                                        const double tmp25 = w45*(-C_2_0 - C_2_2);
-                                        const double tmp26 = w36*(C_0_5 + C_0_7);
-                                        const double tmp27 = w40*(C_1_2 + C_1_7);
-                                        const double tmp28 = w33*(C_0_4 + C_0_6);
-                                        const double tmp29 = w46*(-C_2_1 - C_2_3);
-                                        const double tmp30 = w38*(C_2_0 + C_2_2);
-                                        const double tmp31 = w35*(C_2_1 + C_2_3);
-                                        const double tmp32 = w41*(-C_0_4 - C_0_6);
-                                        const double tmp33 = w37*(-C_1_2 - C_1_7);
-                                        const double tmp34 = w39*(-C_0_5 - C_0_7);
-                                        const double tmp35 = w45*(C_2_5 + C_2_7);
-                                        const double tmp36 = w36*(-C_0_0 - C_0_2);
-                                        const double tmp37 = w40*(-C_1_0 - C_1_5);
-                                        const double tmp38 = w33*(-C_0_1 - C_0_3);
-                                        const double tmp39 = w46*(C_2_4 + C_2_6);
-                                        const double tmp40 = w38*(-C_2_0 - C_2_1 - C_2_2 - C_2_3);
-                                        const double tmp41 = w42*(-C_1_2 - C_1_3);
-                                        const double tmp42 = w41*(-C_0_1 - C_0_3);
-                                        const double tmp43 = w37*(-C_1_0 - C_1_1);
-                                        const double tmp44 = w39*(-C_0_0 - C_0_2);
-                                        const double tmp45 = w45*(-C_2_4 - C_2_5 - C_2_6 - C_2_7);
-                                        const double tmp46 = w36*(-C_0_5 - C_0_7);
-                                        const double tmp47 = w40*(-C_1_6 - C_1_7);
-                                        const double tmp48 = w33*(-C_0_4 - C_0_6);
-                                        const double tmp49 = w34*(-C_1_4 - C_1_5);
-                                        const double tmp50 = w38*(C_2_0 + C_2_1);
-                                        const double tmp51 = w42*(-C_1_4 - C_1_5);
-                                        const double tmp52 = w35*(C_2_2 + C_2_3);
-                                        const double tmp53 = w37*(-C_1_6 - C_1_7);
-                                        const double tmp54 = w39*(-C_0_1 - C_0_7);
-                                        const double tmp55 = w45*(C_2_6 + C_2_7);
-                                        const double tmp56 = w36*(-C_0_0 - C_0_6);
-                                        const double tmp57 = w40*(-C_1_0 - C_1_1);
-                                        const double tmp58 = w46*(C_2_4 + C_2_5);
-                                        const double tmp59 = w34*(-C_1_2 - C_1_3);
-                                        const double tmp60 = w38*(C_2_0 + C_2_1 + C_2_2 + C_2_3);
-                                        const double tmp61 = w37*(C_1_0 + C_1_1 + C_1_4 + C_1_5);
-                                        const double tmp62 = w39*(C_0_0 + C_0_2 + C_0_4 + C_0_6);
-                                        const double tmp63 = w45*(C_2_4 + C_2_5 + C_2_6 + C_2_7);
-                                        const double tmp64 = w36*(C_0_1 + C_0_3 + C_0_5 + C_0_7);
-                                        const double tmp65 = w40*(C_1_2 + C_1_3 + C_1_6 + C_1_7);
-                                        const double tmp66 = w41*(-C_0_5 - C_0_7);
-                                        const double tmp67 = w39*(-C_0_4 - C_0_6);
-                                        const double tmp68 = w36*(-C_0_1 - C_0_3);
-                                        const double tmp69 = w33*(-C_0_0 - C_0_2);
-                                        const double tmp70 = w38*(C_2_0 + C_2_3);
-                                        const double tmp71 = w42*(C_1_2 + C_1_6);
-                                        const double tmp72 = w41*(-C_0_2 - C_0_6);
-                                        const double tmp73 = w37*(C_1_0 + C_1_4);
-                                        const double tmp74 = w39*(-C_0_3 - C_0_7);
-                                        const double tmp75 = w45*(C_2_4 + C_2_7);
-                                        const double tmp76 = w36*(-C_0_0 - C_0_4);
-                                        const double tmp77 = w40*(C_1_3 + C_1_7);
-                                        const double tmp78 = w33*(-C_0_1 - C_0_5);
-                                        const double tmp79 = w34*(C_1_1 + C_1_5);
-                                        const double tmp80 = w39*(-C_0_1 - C_0_3 - C_0_5 - C_0_7);
-                                        const double tmp81 = w36*(-C_0_0 - C_0_2 - C_0_4 - C_0_6);
-                                        const double tmp82 = w38*(-C_2_4 - C_2_7);
-                                        const double tmp83 = w42*(-C_1_1 - C_1_5);
-                                        const double tmp84 = w41*(C_0_1 + C_0_5);
-                                        const double tmp85 = w37*(-C_1_3 - C_1_7);
-                                        const double tmp86 = w39*(C_0_0 + C_0_4);
-                                        const double tmp87 = w45*(-C_2_0 - C_2_3);
-                                        const double tmp88 = w36*(C_0_3 + C_0_7);
-                                        const double tmp89 = w40*(-C_1_0 - C_1_4);
-                                        const double tmp90 = w33*(C_0_2 + C_0_6);
-                                        const double tmp91 = w34*(-C_1_2 - C_1_6);
-                                        const double tmp92 = w38*(C_2_1 + C_2_2);
-                                        const double tmp93 = w45*(C_2_5 + C_2_6);
-                                        const double tmp94 = w37*(-C_1_2 - C_1_3 - C_1_6 - C_1_7);
-                                        const double tmp95 = w40*(-C_1_0 - C_1_1 - C_1_4 - C_1_5);
-                                        const double tmp96 = w42*(C_1_0 + C_1_1);
-                                        const double tmp97 = w41*(C_0_0 + C_0_2);
-                                        const double tmp98 = w37*(C_1_2 + C_1_3);
-                                        const double tmp99 = w39*(C_0_1 + C_0_3);
-                                        const double tmp100 = w36*(C_0_4 + C_0_6);
-                                        const double tmp101 = w40*(C_1_4 + C_1_5);
-                                        const double tmp102 = w33*(C_0_5 + C_0_7);
-                                        const double tmp103 = w34*(C_1_6 + C_1_7);
-                                        const double tmp104 = w38*(-C_2_2 - C_2_3);
-                                        const double tmp105 = w35*(-C_2_0 - C_2_1);
-                                        const double tmp106 = w41*(-C_0_3 - C_0_7);
-                                        const double tmp107 = w37*(C_1_2 + C_1_3 + C_1_6 + C_1_7);
-                                        const double tmp108 = w39*(-C_0_2 - C_0_6);
-                                        const double tmp109 = w45*(-C_2_4 - C_2_5);
-                                        const double tmp110 = w36*(-C_0_1 - C_0_5);
-                                        const double tmp111 = w40*(C_1_0 + C_1_1 + C_1_4 + C_1_5);
-                                        const double tmp112 = w33*(-C_0_0 - C_0_4);
-                                        const double tmp113 = w46*(-C_2_6 - C_2_7);
-                                        const double tmp114 = w42*(-C_1_0 - C_1_4);
-                                        const double tmp115 = w41*(-C_0_0 - C_0_4);
-                                        const double tmp116 = w37*(-C_1_2 - C_1_6);
-                                        const double tmp117 = w39*(-C_0_1 - C_0_5);
-                                        const double tmp118 = w36*(-C_0_2 - C_0_6);
-                                        const double tmp119 = w40*(-C_1_1 - C_1_5);
-                                        const double tmp120 = w33*(-C_0_3 - C_0_7);
-                                        const double tmp121 = w34*(-C_1_3 - C_1_7);
-                                        const double tmp122 = w38*(C_2_2 + C_2_3);
-                                        const double tmp123 = w42*(C_1_6 + C_1_7);
-                                        const double tmp124 = w35*(C_2_0 + C_2_1);
-                                        const double tmp125 = w37*(C_1_4 + C_1_5);
-                                        const double tmp126 = w39*(C_0_2 + C_0_4);
-                                        const double tmp127 = w45*(C_2_4 + C_2_5);
-                                        const double tmp128 = w36*(C_0_3 + C_0_5);
-                                        const double tmp129 = w40*(C_1_2 + C_1_3);
-                                        const double tmp130 = w46*(C_2_6 + C_2_7);
-                                        const double tmp131 = w34*(C_1_0 + C_1_1);
-                                        const double tmp132 = w38*(-C_2_1 - C_2_2);
-                                        const double tmp133 = w37*(C_1_2 + C_1_7);
-                                        const double tmp134 = w39*(C_0_1 + C_0_7);
-                                        const double tmp135 = w36*(C_0_0 + C_0_6);
-                                        const double tmp136 = w40*(C_1_0 + C_1_5);
-                                        const double tmp137 = w45*(-C_2_5 - C_2_6);
-                                        const double tmp138 = w38*(-C_2_4 - C_2_6);
-                                        const double tmp139 = w35*(-C_2_5 - C_2_7);
-                                        const double tmp140 = w41*(-C_0_0 - C_0_2);
-                                        const double tmp141 = w37*(-C_1_3 - C_1_6);
-                                        const double tmp142 = w39*(-C_0_1 - C_0_3);
-                                        const double tmp143 = w45*(-C_2_1 - C_2_3);
-                                        const double tmp144 = w36*(-C_0_4 - C_0_6);
-                                        const double tmp145 = w40*(-C_1_1 - C_1_4);
-                                        const double tmp146 = w33*(-C_0_5 - C_0_7);
-                                        const double tmp147 = w46*(-C_2_0 - C_2_2);
-                                        const double tmp148 = w39*(-C_0_3 - C_0_5);
-                                        const double tmp149 = w36*(-C_0_2 - C_0_4);
-                                        const double tmp150 = w38*(C_2_5 + C_2_6);
-                                        const double tmp151 = w37*(-C_1_0 - C_1_5);
-                                        const double tmp152 = w39*(-C_0_0 - C_0_6);
-                                        const double tmp153 = w45*(C_2_1 + C_2_2);
-                                        const double tmp154 = w36*(-C_0_1 - C_0_7);
-                                        const double tmp155 = w40*(-C_1_2 - C_1_7);
-                                        const double tmp156 = w41*(C_0_2 + C_0_6);
-                                        const double tmp157 = w39*(C_0_3 + C_0_7);
-                                        const double tmp158 = w36*(C_0_0 + C_0_4);
-                                        const double tmp159 = w33*(C_0_1 + C_0_5);
-                                        const double tmp160 = w38*(C_2_6 + C_2_7);
-                                        const double tmp161 = w35*(C_2_4 + C_2_5);
-                                        const double tmp162 = w45*(C_2_0 + C_2_1);
-                                        const double tmp163 = w46*(C_2_2 + C_2_3);
-                                        const double tmp164 = w38*(-C_2_0 - C_2_3);
-                                        const double tmp165 = w37*(C_1_3 + C_1_6);
-                                        const double tmp166 = w40*(C_1_1 + C_1_4);
-                                        const double tmp167 = w45*(-C_2_4 - C_2_7);
-                                        const double tmp168 = w39*(C_0_3 + C_0_5);
-                                        const double tmp169 = w36*(C_0_2 + C_0_4);
-                                        const double tmp170 = w38*(C_2_1 + C_2_3);
-                                        const double tmp171 = w35*(C_2_0 + C_2_2);
-                                        const double tmp172 = w41*(C_0_5 + C_0_7);
-                                        const double tmp173 = w37*(C_1_1 + C_1_4);
-                                        const double tmp174 = w39*(C_0_4 + C_0_6);
-                                        const double tmp175 = w45*(C_2_4 + C_2_6);
-                                        const double tmp176 = w36*(C_0_1 + C_0_3);
-                                        const double tmp177 = w40*(C_1_3 + C_1_6);
-                                        const double tmp178 = w33*(C_0_0 + C_0_2);
-                                        const double tmp179 = w46*(C_2_5 + C_2_7);
-                                        const double tmp180 = w38*(-C_2_1 - C_2_3);
-                                        const double tmp181 = w42*(C_1_1 + C_1_5);
-                                        const double tmp182 = w35*(-C_2_0 - C_2_2);
-                                        const double tmp183 = w37*(C_1_3 + C_1_7);
-                                        const double tmp184 = w39*(C_0_1 + C_0_3 + C_0_5 + C_0_7);
-                                        const double tmp185 = w45*(-C_2_4 - C_2_6);
-                                        const double tmp186 = w36*(C_0_0 + C_0_2 + C_0_4 + C_0_6);
-                                        const double tmp187 = w40*(C_1_0 + C_1_4);
-                                        const double tmp188 = w46*(-C_2_5 - C_2_7);
-                                        const double tmp189 = w34*(C_1_2 + C_1_6);
-                                        const double tmp190 = w38*(-C_2_0 - C_2_1);
-                                        const double tmp191 = w35*(-C_2_2 - C_2_3);
-                                        const double tmp192 = w41*(C_0_0 + C_0_4);
-                                        const double tmp193 = w37*(-C_1_0 - C_1_1 - C_1_4 - C_1_5);
-                                        const double tmp194 = w39*(C_0_1 + C_0_5);
-                                        const double tmp195 = w45*(-C_2_6 - C_2_7);
-                                        const double tmp196 = w36*(C_0_2 + C_0_6);
-                                        const double tmp197 = w40*(-C_1_2 - C_1_3 - C_1_6 - C_1_7);
-                                        const double tmp198 = w33*(C_0_3 + C_0_7);
-                                        const double tmp199 = w46*(-C_2_4 - C_2_5);
-                                        const double tmp200 = w38*(-C_2_6 - C_2_7);
-                                        const double tmp201 = w42*(C_1_2 + C_1_3);
-                                        const double tmp202 = w35*(-C_2_4 - C_2_5);
-                                        const double tmp203 = w37*(C_1_0 + C_1_1);
-                                        const double tmp204 = w45*(-C_2_0 - C_2_1);
-                                        const double tmp205 = w40*(C_1_6 + C_1_7);
-                                        const double tmp206 = w46*(-C_2_2 - C_2_3);
-                                        const double tmp207 = w34*(C_1_4 + C_1_5);
-                                        const double tmp208 = w37*(-C_1_1 - C_1_4);
-                                        const double tmp209 = w39*(-C_0_2 - C_0_4);
-                                        const double tmp210 = w36*(-C_0_3 - C_0_5);
-                                        const double tmp211 = w40*(-C_1_3 - C_1_6);
-                                        const double tmp212 = w38*(C_2_4 + C_2_7);
-                                        const double tmp213 = w45*(C_2_0 + C_2_3);
-                                        const double tmp214 = w41*(-C_0_1 - C_0_5);
-                                        const double tmp215 = w39*(-C_0_0 - C_0_4);
-                                        const double tmp216 = w36*(-C_0_3 - C_0_7);
-                                        const double tmp217 = w33*(-C_0_2 - C_0_6);
-                                        const double tmp218 = w42*(-C_1_3 - C_1_7);
-                                        const double tmp219 = w37*(-C_1_1 - C_1_5);
-                                        const double tmp220 = w40*(-C_1_2 - C_1_6);
-                                        const double tmp221 = w34*(-C_1_0 - C_1_4);
-                                        const double tmp222 = w39*(C_0_0 + C_0_6);
-                                        const double tmp223 = w36*(C_0_1 + C_0_7);
-                                        const double tmp224 = w38*(C_2_4 + C_2_5);
-                                        const double tmp225 = w35*(C_2_6 + C_2_7);
-                                        const double tmp226 = w45*(C_2_2 + C_2_3);
-                                        const double tmp227 = w46*(C_2_0 + C_2_1);
-                                        const double tmp228 = w38*(-C_2_0 - C_2_2);
-                                        const double tmp229 = w42*(-C_1_2 - C_1_6);
-                                        const double tmp230 = w35*(-C_2_1 - C_2_3);
-                                        const double tmp231 = w37*(-C_1_0 - C_1_4);
-                                        const double tmp232 = w39*(-C_0_0 - C_0_2 - C_0_4 - C_0_6);
-                                        const double tmp233 = w45*(-C_2_5 - C_2_7);
-                                        const double tmp234 = w36*(-C_0_1 - C_0_3 - C_0_5 - C_0_7);
-                                        const double tmp235 = w40*(-C_1_3 - C_1_7);
-                                        const double tmp236 = w46*(-C_2_4 - C_2_6);
-                                        const double tmp237 = w34*(-C_1_1 - C_1_5);
-                                        const double tmp238 = w42*(C_1_0 + C_1_4);
-                                        const double tmp239 = w37*(C_1_2 + C_1_6);
-                                        const double tmp240 = w40*(C_1_1 + C_1_5);
-                                        const double tmp241 = w34*(C_1_3 + C_1_7);
-                                        const double tmp242 = w38*(-C_2_4 - C_2_5);
-                                        const double tmp243 = w42*(-C_1_0 - C_1_1);
-                                        const double tmp244 = w35*(-C_2_6 - C_2_7);
-                                        const double tmp245 = w37*(-C_1_2 - C_1_3);
-                                        const double tmp246 = w45*(-C_2_2 - C_2_3);
-                                        const double tmp247 = w40*(-C_1_4 - C_1_5);
-                                        const double tmp248 = w46*(-C_2_0 - C_2_1);
-                                        const double tmp249 = w34*(-C_1_6 - C_1_7);
-                                        const double tmp250 = w42*(-C_1_6 - C_1_7);
-                                        const double tmp251 = w37*(-C_1_4 - C_1_5);
-                                        const double tmp252 = w40*(-C_1_2 - C_1_3);
-                                        const double tmp253 = w34*(-C_1_0 - C_1_1);
-                                        const double tmp254 = w38*(C_2_5 + C_2_7);
-                                        const double tmp255 = w35*(C_2_4 + C_2_6);
-                                        const double tmp256 = w45*(C_2_0 + C_2_2);
-                                        const double tmp257 = w46*(C_2_1 + C_2_3);
-                                        const double tmp258 = w38*(-C_2_4 - C_2_5 - C_2_6 - C_2_7);
-                                        const double tmp259 = w45*(-C_2_0 - C_2_1 - C_2_2 - C_2_3);
-                                        const double tmp260 = w38*(C_2_4 + C_2_6);
-                                        const double tmp261 = w35*(C_2_5 + C_2_7);
-                                        const double tmp262 = w45*(C_2_1 + C_2_3);
-                                        const double tmp263 = w46*(C_2_0 + C_2_2);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-C_0_0*w50 - C_0_1*w41 - C_0_6*w33 - C_0_7*w49 + C_1_0*w47 - C_1_2*w42 - C_1_5*w34 + C_1_7*w48 - C_2_0*w43 - C_2_3*w35 - C_2_4*w46 - C_2_7*w44 + tmp132 + tmp137 + tmp208 + tmp209 + tmp210 + tmp211;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=C_0_0*w50 + C_0_1*w41 + C_0_6*w33 + C_0_7*w49 + tmp126 + tmp128 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-C_1_0*w47 + C_1_2*w42 + C_1_5*w34 - C_1_7*w48 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp146 + tmp147 + tmp173 + tmp177;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp40 + tmp45 + tmp96 + tmp97 + tmp98 + tmp99;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=C_2_0*w43 + C_2_3*w35 + C_2_4*w46 + C_2_7*w44 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp192 + tmp193 + tmp194 + tmp196 + tmp197 + tmp198 + tmp224 + tmp225 + tmp226 + tmp227;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp232 + tmp234 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-C_0_0*w41 - C_0_1*w50 - C_0_6*w49 - C_0_7*w33 + tmp148 + tmp149 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=C_0_0*w41 + C_0_1*w50 + C_0_6*w49 + C_0_7*w33 + C_1_1*w47 - C_1_3*w42 - C_1_4*w34 + C_1_6*w48 - C_2_1*w43 - C_2_2*w35 - C_2_5*w46 - C_2_6*w44 + tmp151 + tmp155 + tmp164 + tmp167 + tmp168 + tmp169;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp101 + tmp103 + tmp40 + tmp42 + tmp44 + tmp45 + tmp46 + tmp48 + tmp96 + tmp98;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-C_1_1*w47 + C_1_3*w42 + C_1_4*w34 - C_1_6*w48 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp193 + tmp197 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=C_2_1*w43 + C_2_2*w35 + C_2_5*w46 + C_2_6*w44 + tmp70 + tmp75 + tmp83 + tmp84 + tmp85 + tmp86 + tmp88 + tmp89 + tmp90 + tmp91;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp60 + tmp61 + tmp63 + tmp65 + tmp80 + tmp81;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp181 + tmp183 + tmp184 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-C_1_0*w42 + C_1_2*w47 + C_1_5*w48 - C_1_7*w34 + tmp138 + tmp139 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp100 + tmp102 + tmp40 + tmp41 + tmp43 + tmp45 + tmp47 + tmp49 + tmp97 + tmp99;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-C_0_2*w50 - C_0_3*w41 - C_0_4*w33 - C_0_5*w49 + C_1_0*w42 - C_1_2*w47 - C_1_5*w48 + C_1_7*w34 - C_2_1*w35 - C_2_2*w43 - C_2_5*w44 - C_2_6*w46 + tmp152 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=C_0_2*w50 + C_0_3*w41 + C_0_4*w33 + C_0_5*w49 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp229 + tmp231 + tmp232 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp60 + tmp62 + tmp63 + tmp64 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=C_2_1*w35 + C_2_2*w43 + C_2_5*w44 + C_2_6*w46 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp107 + tmp111 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-C_1_1*w42 + C_1_3*w47 + C_1_4*w48 - C_1_6*w34 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp28 + tmp29 + tmp33 + tmp37;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-C_0_2*w41 - C_0_3*w50 - C_0_4*w49 - C_0_5*w33 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp54 + tmp56;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=C_0_2*w41 + C_0_3*w50 + C_0_4*w49 + C_0_5*w33 + C_1_1*w42 - C_1_3*w47 - C_1_4*w48 + C_1_6*w34 - C_2_0*w35 - C_2_3*w43 - C_2_4*w44 - C_2_7*w46 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp60 + tmp63 + tmp80 + tmp81 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp184 + tmp186 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp106 + tmp107 + tmp108 + tmp110 + tmp111 + tmp112 + tmp160 + tmp161 + tmp162 + tmp163;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=C_2_0*w35 + C_2_3*w43 + C_2_4*w44 + C_2_7*w46 + tmp1 + tmp2 + tmp3 + tmp4 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-C_2_0*w46 - C_2_3*w44 - C_2_4*w43 - C_2_7*w35 + tmp0 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp5;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp228 + tmp230 + tmp232 + tmp233 + tmp234 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp62 + tmp64 + tmp65;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-C_0_2*w33 - C_0_3*w49 - C_0_4*w50 - C_0_5*w41 - C_1_1*w34 + C_1_3*w48 + C_1_4*w47 - C_1_6*w42 + C_2_0*w46 + C_2_3*w44 + C_2_4*w43 + C_2_7*w35 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=C_0_2*w33 + C_0_3*w49 + C_0_4*w50 + C_0_5*w41 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp55 + tmp57 + tmp58 + tmp59;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=C_1_1*w34 - C_1_3*w48 - C_1_4*w47 + C_1_6*w42 + tmp23 + tmp27 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp38 + tmp39;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp190 + tmp191 + tmp193 + tmp195 + tmp197 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-C_2_1*w46 - C_2_2*w44 - C_2_5*w43 - C_2_6*w35 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp65 + tmp80 + tmp81;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-C_0_2*w49 - C_0_3*w33 - C_0_4*w41 - C_0_5*w50 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=C_0_2*w49 + C_0_3*w33 + C_0_4*w41 + C_0_5*w50 - C_1_0*w34 + C_1_2*w48 + C_1_5*w47 - C_1_7*w42 + C_2_1*w46 + C_2_2*w44 + C_2_5*w43 + C_2_6*w35 + tmp134 + tmp135 + tmp208 + tmp211 + tmp212 + tmp213;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp10 + tmp11 + tmp13 + tmp15 + tmp17 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=C_1_0*w34 - C_1_2*w48 - C_1_5*w47 + C_1_7*w42 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233 + tmp234 + tmp235 + tmp236 + tmp237;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp258 + tmp259 + tmp62 + tmp64 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-C_2_1*w44 - C_2_2*w46 - C_2_5*w35 - C_2_6*w43 + tmp71 + tmp72 + tmp73 + tmp74 + tmp76 + tmp77 + tmp78 + tmp79 + tmp82 + tmp87;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp104 + tmp105 + tmp107 + tmp109 + tmp111 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=C_1_1*w48 - C_1_3*w34 - C_1_4*w42 + C_1_6*w47 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp10 + tmp12 + tmp14 + tmp15 + tmp16 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-C_0_0*w33 - C_0_1*w49 - C_0_6*w50 - C_0_7*w41 - C_1_1*w48 + C_1_3*w34 + C_1_4*w42 - C_1_6*w47 + C_2_1*w44 + C_2_2*w46 + C_2_5*w35 + C_2_6*w43 + tmp133 + tmp136 + tmp209 + tmp210 + tmp212 + tmp213;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=C_0_0*w33 + C_0_1*w49 + C_0_6*w50 + C_0_7*w41 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp258 + tmp259 + tmp80 + tmp81 + tmp94 + tmp95;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp180 + tmp182 + tmp184 + tmp185 + tmp186 + tmp188 + tmp218 + tmp219 + tmp220 + tmp221;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-C_2_0*w44 - C_2_3*w46 - C_2_4*w35 - C_2_7*w43 + tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp10 + tmp15 + tmp250 + tmp251 + tmp252 + tmp253 + tmp66 + tmp67 + tmp68 + tmp69;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=C_1_0*w48 - C_1_2*w34 - C_1_5*w42 + C_1_7*w47 + tmp141 + tmp145 + tmp170 + tmp171 + tmp172 + tmp174 + tmp175 + tmp176 + tmp178 + tmp179;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-C_0_0*w49 - C_0_1*w33 - C_0_6*w41 - C_0_7*w50 + tmp122 + tmp123 + tmp124 + tmp125 + tmp127 + tmp129 + tmp130 + tmp131 + tmp148 + tmp149;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=C_0_0*w49 + C_0_1*w33 + C_0_6*w41 + C_0_7*w50 - C_1_0*w48 + C_1_2*w34 + C_1_5*w42 - C_1_7*w47 + C_2_0*w44 + C_2_3*w46 + C_2_4*w35 + C_2_7*w43 + tmp150 + tmp153 + tmp165 + tmp166 + tmp168 + tmp169;
-                                    }
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double wC0 = C_p[INDEX3(k,m,0,numEq,numComp)]*w55;
-                                        const double wC1 = C_p[INDEX3(k,m,1,numEq,numComp)]*w56;
-                                        const double wC2 = C_p[INDEX3(k,m,2,numEq,numComp)]*w54;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+= 4*wC0 + 4*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-4*wC0 + 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+= 2*wC0 - 4*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=-2*wC0 - 2*wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+= 2*wC0 + 2*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=-2*wC0 +   wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=   wC0 - 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=  -wC0 -   wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+= 4*wC0 + 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=-4*wC0 + 4*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+= 2*wC0 - 2*wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-2*wC0 - 4*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+= 2*wC0 +   wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-2*wC0 + 2*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=   wC0 -   wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  -wC0 - 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+= 2*wC0 + 4*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=-2*wC0 + 2*wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+= 4*wC0 - 4*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-4*wC0 - 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=   wC0 + 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=  -wC0 +   wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+= 2*wC0 - 2*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=-2*wC0 -   wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+= 2*wC0 + 2*wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-2*wC0 + 4*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+= 4*wC0 - 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=-4*wC0 - 4*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=   wC0 +   wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  -wC0 + 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+= 2*wC0 -   wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-2*wC0 - 2*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+= 2*wC0 + 2*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=-2*wC0 +   wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=   wC0 - 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=  -wC0 -   wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+= 4*wC0 + 4*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-4*wC0 + 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+= 2*wC0 - 4*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=-2*wC0 - 2*wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+= 2*wC0 +   wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-2*wC0 + 2*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=   wC0 -   wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  -wC0 - 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+= 4*wC0 + 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=-4*wC0 + 4*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+= 2*wC0 - 2*wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=-2*wC0 - 4*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=   wC0 + 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=  -wC0 +   wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+= 2*wC0 - 2*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=-2*wC0 -   wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+= 2*wC0 + 4*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=-2*wC0 + 2*wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+= 4*wC0 - 4*wC1 - 4*wC2;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-4*wC0 - 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=   wC0 +   wC1 +   wC2;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  -wC0 + 2*wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+= 2*wC0 -   wC1 + 2*wC2;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-2*wC0 - 2*wC1 + 4*wC2;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+= 2*wC0 + 2*wC1 -   wC2;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=-2*wC0 + 4*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+= 4*wC0 - 2*wC1 - 2*wC2;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=-4*wC0 - 4*wC1 - 4*wC2;
-                                    }
-                                }
-                            }
-                        }
-                        ///////////////
-                        // process D //
-                        ///////////////
-                        if (!D.isEmpty()) {
-                            add_EM_S=true;
-                            const double* D_p=D.getSampleDataRO(e);
-                            if (D.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double D_0 = D_p[INDEX3(k,m,0,numEq,numComp)];
-                                        const double D_1 = D_p[INDEX3(k,m,1,numEq,numComp)];
-                                        const double D_2 = D_p[INDEX3(k,m,2,numEq,numComp)];
-                                        const double D_3 = D_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double D_4 = D_p[INDEX3(k,m,4,numEq,numComp)];
-                                        const double D_5 = D_p[INDEX3(k,m,5,numEq,numComp)];
-                                        const double D_6 = D_p[INDEX3(k,m,6,numEq,numComp)];
-                                        const double D_7 = D_p[INDEX3(k,m,7,numEq,numComp)];
-                                        const double tmp0 = w59*(D_3 + D_7);
-                                        const double tmp1 = w57*(D_0 + D_4);
-                                        const double tmp2 = w58*(D_1 + D_2 + D_5 + D_6);
-                                        const double tmp3 = w60*(D_0 + D_1 + D_2 + D_3);
-                                        const double tmp4 = w61*(D_4 + D_5 + D_6 + D_7);
-                                        const double tmp5 = w59*(D_1 + D_3);
-                                        const double tmp6 = w57*(D_4 + D_6);
-                                        const double tmp7 = w58*(D_0 + D_2 + D_5 + D_7);
-                                        const double tmp8 = w59*(D_4 + D_6);
-                                        const double tmp9 = w57*(D_1 + D_3);
-                                        const double tmp10 = w60*(D_4 + D_5 + D_6 + D_7);
-                                        const double tmp11 = w61*(D_0 + D_1 + D_2 + D_3);
-                                        const double tmp12 = w59*(D_4 + D_5);
-                                        const double tmp13 = w57*(D_2 + D_3);
-                                        const double tmp14 = w58*(D_0 + D_1 + D_6 + D_7);
-                                        const double tmp15 = w58*(D_0 + D_1 + D_2 + D_3 + D_4 + D_5 + D_6 + D_7);
-                                        const double tmp16 = w59*(D_2 + D_6);
-                                        const double tmp17 = w57*(D_1 + D_5);
-                                        const double tmp18 = w58*(D_0 + D_3 + D_4 + D_7);
-                                        const double tmp19 = w59*(D_1 + D_5);
-                                        const double tmp20 = w57*(D_2 + D_6);
-                                        const double tmp21 = w60*(D_0 + D_1 + D_4 + D_5);
-                                        const double tmp22 = w61*(D_2 + D_3 + D_6 + D_7);
-                                        const double tmp23 = w59*(D_0 + D_4);
-                                        const double tmp24 = w57*(D_3 + D_7);
-                                        const double tmp25 = w59*(D_6 + D_7);
-                                        const double tmp26 = w57*(D_0 + D_1);
-                                        const double tmp27 = w58*(D_2 + D_3 + D_4 + D_5);
-                                        const double tmp28 = w60*(D_0 + D_5 + D_6);
-                                        const double tmp29 = w61*(D_1 + D_2 + D_7);
-                                        const double tmp30 = w59*(D_0 + D_2);
-                                        const double tmp31 = w57*(D_5 + D_7);
-                                        const double tmp32 = w58*(D_1 + D_3 + D_4 + D_6);
-                                        const double tmp33 = w60*(D_1 + D_2 + D_7);
-                                        const double tmp34 = w61*(D_0 + D_5 + D_6);
-                                        const double tmp35 = w60*(D_1 + D_4 + D_7);
-                                        const double tmp36 = w61*(D_0 + D_3 + D_6);
-                                        const double tmp37 = w60*(D_1 + D_2 + D_4);
-                                        const double tmp38 = w61*(D_3 + D_5 + D_6);
-                                        const double tmp39 = w59*(D_5 + D_7);
-                                        const double tmp40 = w57*(D_0 + D_2);
-                                        const double tmp41 = w60*(D_0 + D_2 + D_4 + D_6);
-                                        const double tmp42 = w61*(D_1 + D_3 + D_5 + D_7);
-                                        const double tmp43 = w60*(D_2 + D_3 + D_6 + D_7);
-                                        const double tmp44 = w61*(D_0 + D_1 + D_4 + D_5);
-                                        const double tmp45 = w60*(D_2 + D_4 + D_7);
-                                        const double tmp46 = w61*(D_0 + D_3 + D_5);
-                                        const double tmp47 = w59*(D_2 + D_3);
-                                        const double tmp48 = w57*(D_4 + D_5);
-                                        const double tmp49 = w60*(D_3 + D_5 + D_6);
-                                        const double tmp50 = w61*(D_1 + D_2 + D_4);
-                                        const double tmp51 = w60*(D_0 + D_3 + D_5);
-                                        const double tmp52 = w61*(D_2 + D_4 + D_7);
-                                        const double tmp53 = w60*(D_0 + D_3 + D_6);
-                                        const double tmp54 = w61*(D_1 + D_4 + D_7);
-                                        const double tmp55 = w60*(D_1 + D_3 + D_5 + D_7);
-                                        const double tmp56 = w61*(D_0 + D_2 + D_4 + D_6);
-                                        const double tmp57 = w59*(D_0 + D_1);
-                                        const double tmp58 = w57*(D_6 + D_7);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=D_0*w62 + D_7*w63 + tmp49 + tmp50;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp27 + tmp57 + tmp58;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp30 + tmp31 + tmp32;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp10 + tmp11;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp2 + tmp23 + tmp24;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp43 + tmp44;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp55 + tmp56;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp27 + tmp57 + tmp58;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=D_1*w62 + D_6*w63 + tmp45 + tmp46;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp10 + tmp11;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp5 + tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp43 + tmp44;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp18 + tmp19 + tmp20;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp41 + tmp42;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp30 + tmp31 + tmp32;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp10 + tmp11;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=D_2*w62 + D_5*w63 + tmp35 + tmp36;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp14 + tmp47 + tmp48;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp55 + tmp56;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp16 + tmp17 + tmp18;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp21 + tmp22;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp10 + tmp11;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp5 + tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp14 + tmp47 + tmp48;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=D_3*w62 + D_4*w63 + tmp28 + tmp29;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp41 + tmp42;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp21 + tmp22;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0 + tmp1 + tmp2;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp2 + tmp23 + tmp24;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp43 + tmp44;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp55 + tmp56;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=D_3*w63 + D_4*w62 + tmp33 + tmp34;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp12 + tmp13 + tmp14;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp7 + tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp43 + tmp44;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp18 + tmp19 + tmp20;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp41 + tmp42;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp12 + tmp13 + tmp14;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=D_2*w63 + D_5*w62 + tmp53 + tmp54;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp32 + tmp39 + tmp40;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp55 + tmp56;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp16 + tmp17 + tmp18;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp21 + tmp22;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp7 + tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=D_1*w63 + D_6*w62 + tmp51 + tmp52;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp25 + tmp26 + tmp27;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp15;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp41 + tmp42;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp21 + tmp22;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1 + tmp2;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp32 + tmp39 + tmp40;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp25 + tmp26 + tmp27;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=D_0*w63 + D_7*w62 + tmp37 + tmp38;
-                                    }
-                                 }
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            if (d.actsExpanded()) {
+                                const double d_0 = d_p[0];
+                                const double d_1 = d_p[1];
+                                const double d_2 = d_p[2];
+                                const double d_3 = d_p[3];
+                                const double tmp0 = w10*(d_0 + d_2);
+                                const double tmp1 = w11*(d_1 + d_3);
+                                const double tmp2 = w12*(d_0 + d_1 + d_2 + d_3);
+                                const double tmp3 = w12*(d_1 + d_2);
+                                const double tmp4 = w10*(d_1 + d_3);
+                                const double tmp5 = w11*(d_0 + d_2);
+                                const double tmp6 = w12*(d_0 + d_3);
+                                const double tmp7 = w10*(d_0 + d_1);
+                                const double tmp8 = w11*(d_2 + d_3);
+                                const double tmp9 = w10*(d_2 + d_3);
+                                const double tmp10 = w11*(d_0 + d_1);
+                                EM_S[INDEX2(0,0,8)] = d_0*w14 + d_3*w13 + tmp3;
+                                EM_S[INDEX2(1,0,8)] = tmp10 + tmp9;
+                                EM_S[INDEX2(2,0,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(3,0,8)] = tmp2;
+                                EM_S[INDEX2(0,1,8)] = tmp10 + tmp9;
+                                EM_S[INDEX2(1,1,8)] = d_1*w14 + d_2*w13 + tmp6;
+                                EM_S[INDEX2(2,1,8)] = tmp2;
+                                EM_S[INDEX2(3,1,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(0,2,8)] = tmp4 + tmp5;
+                                EM_S[INDEX2(1,2,8)] = tmp2;
+                                EM_S[INDEX2(2,2,8)] = d_1*w13 + d_2*w14 + tmp6;
+                                EM_S[INDEX2(3,2,8)] = tmp7 + tmp8;
+                                EM_S[INDEX2(0,3,8)] = tmp2;
+                                EM_S[INDEX2(1,3,8)] = tmp0 + tmp1;
+                                EM_S[INDEX2(2,3,8)] = tmp7 + tmp8;
+                                EM_S[INDEX2(3,3,8)] = d_0*w13 + d_3*w14 + tmp3;
                             } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double wD0 = 8*D_p[INDEX2(k, m, numEq)]*w58;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=8*wD0;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=  wD0;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=2*wD0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=4*wD0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=8*wD0;
-                                    }
-                                }
+                                const double wd0 = 4*d_p[0]*w12;
+                                EM_S[INDEX2(0,0,8)] = 4*wd0;
+                                EM_S[INDEX2(1,0,8)] = 2*wd0;
+                                EM_S[INDEX2(2,0,8)] = 2*wd0;
+                                EM_S[INDEX2(3,0,8)] =   wd0;
+                                EM_S[INDEX2(0,1,8)] = 2*wd0;
+                                EM_S[INDEX2(1,1,8)] = 4*wd0;
+                                EM_S[INDEX2(2,1,8)] =   wd0;
+                                EM_S[INDEX2(3,1,8)] = 2*wd0;
+                                EM_S[INDEX2(0,2,8)] = 2*wd0;
+                                EM_S[INDEX2(1,2,8)] =   wd0;
+                                EM_S[INDEX2(2,2,8)] = 4*wd0;
+                                EM_S[INDEX2(3,2,8)] = 2*wd0;
+                                EM_S[INDEX2(0,3,8)] =   wd0;
+                                EM_S[INDEX2(1,3,8)] = 2*wd0;
+                                EM_S[INDEX2(2,3,8)] = 2*wd0;
+                                EM_S[INDEX2(3,3,8)] = 4*wd0;
                             }
                         }
                         ///////////////
-                        // process X //
+                        // process y //
                         ///////////////
-                        if (!X.isEmpty()) {
-                            add_EM_F=true;
-                            const double* X_p=X.getSampleDataRO(e);
-                            if (X.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double X_0_0 = X_p[INDEX3(k,0,0,numEq,3)];
-                                    const double X_1_0 = X_p[INDEX3(k,1,0,numEq,3)];
-                                    const double X_2_0 = X_p[INDEX3(k,2,0,numEq,3)];
-                                    const double X_0_1 = X_p[INDEX3(k,0,1,numEq,3)];
-                                    const double X_1_1 = X_p[INDEX3(k,1,1,numEq,3)];
-                                    const double X_2_1 = X_p[INDEX3(k,2,1,numEq,3)];
-                                    const double X_0_2 = X_p[INDEX3(k,0,2,numEq,3)];
-                                    const double X_1_2 = X_p[INDEX3(k,1,2,numEq,3)];
-                                    const double X_2_2 = X_p[INDEX3(k,2,2,numEq,3)];
-                                    const double X_0_3 = X_p[INDEX3(k,0,3,numEq,3)];
-                                    const double X_1_3 = X_p[INDEX3(k,1,3,numEq,3)];
-                                    const double X_2_3 = X_p[INDEX3(k,2,3,numEq,3)];
-                                    const double X_0_4 = X_p[INDEX3(k,0,4,numEq,3)];
-                                    const double X_1_4 = X_p[INDEX3(k,1,4,numEq,3)];
-                                    const double X_2_4 = X_p[INDEX3(k,2,4,numEq,3)];
-                                    const double X_0_5 = X_p[INDEX3(k,0,5,numEq,3)];
-                                    const double X_1_5 = X_p[INDEX3(k,1,5,numEq,3)];
-                                    const double X_2_5 = X_p[INDEX3(k,2,5,numEq,3)];
-                                    const double X_0_6 = X_p[INDEX3(k,0,6,numEq,3)];
-                                    const double X_1_6 = X_p[INDEX3(k,1,6,numEq,3)];
-                                    const double X_2_6 = X_p[INDEX3(k,2,6,numEq,3)];
-                                    const double X_0_7 = X_p[INDEX3(k,0,7,numEq,3)];
-                                    const double X_1_7 = X_p[INDEX3(k,1,7,numEq,3)];
-                                    const double X_2_7 = X_p[INDEX3(k,2,7,numEq,3)];
-                                    const double tmp0 = w72*(X_0_6 + X_0_7);
-                                    const double tmp1 = w66*(X_2_0 + X_2_4);
-                                    const double tmp2 = w64*(X_0_0 + X_0_1);
-                                    const double tmp3 = w68*(X_2_1 + X_2_2 + X_2_5 + X_2_6);
-                                    const double tmp4 = w65*(X_1_0 + X_1_2);
-                                    const double tmp5 = w70*(X_2_3 + X_2_7);
-                                    const double tmp6 = w67*(X_1_1 + X_1_3 + X_1_4 + X_1_6);
-                                    const double tmp7 = w71*(X_1_5 + X_1_7);
-                                    const double tmp8 = w69*(X_0_2 + X_0_3 + X_0_4 + X_0_5);
-                                    const double tmp9 = w72*(-X_0_6 - X_0_7);
-                                    const double tmp10 = w66*(X_2_1 + X_2_5);
-                                    const double tmp11 = w64*(-X_0_0 - X_0_1);
-                                    const double tmp12 = w68*(X_2_0 + X_2_3 + X_2_4 + X_2_7);
-                                    const double tmp13 = w65*(X_1_1 + X_1_3);
-                                    const double tmp14 = w70*(X_2_2 + X_2_6);
-                                    const double tmp15 = w67*(X_1_0 + X_1_2 + X_1_5 + X_1_7);
-                                    const double tmp16 = w71*(X_1_4 + X_1_6);
-                                    const double tmp17 = w69*(-X_0_2 - X_0_3 - X_0_4 - X_0_5);
-                                    const double tmp18 = w72*(X_0_4 + X_0_5);
-                                    const double tmp19 = w66*(X_2_2 + X_2_6);
-                                    const double tmp20 = w64*(X_0_2 + X_0_3);
-                                    const double tmp21 = w65*(-X_1_0 - X_1_2);
-                                    const double tmp22 = w70*(X_2_1 + X_2_5);
-                                    const double tmp23 = w67*(-X_1_1 - X_1_3 - X_1_4 - X_1_6);
-                                    const double tmp24 = w71*(-X_1_5 - X_1_7);
-                                    const double tmp25 = w69*(X_0_0 + X_0_1 + X_0_6 + X_0_7);
-                                    const double tmp26 = w72*(-X_0_4 - X_0_5);
-                                    const double tmp27 = w66*(X_2_3 + X_2_7);
-                                    const double tmp28 = w64*(-X_0_2 - X_0_3);
-                                    const double tmp29 = w65*(-X_1_1 - X_1_3);
-                                    const double tmp30 = w70*(X_2_0 + X_2_4);
-                                    const double tmp31 = w67*(-X_1_0 - X_1_2 - X_1_5 - X_1_7);
-                                    const double tmp32 = w71*(-X_1_4 - X_1_6);
-                                    const double tmp33 = w69*(-X_0_0 - X_0_1 - X_0_6 - X_0_7);
-                                    const double tmp34 = w72*(X_0_2 + X_0_3);
-                                    const double tmp35 = w66*(-X_2_0 - X_2_4);
-                                    const double tmp36 = w64*(X_0_4 + X_0_5);
-                                    const double tmp37 = w68*(-X_2_1 - X_2_2 - X_2_5 - X_2_6);
-                                    const double tmp38 = w65*(X_1_4 + X_1_6);
-                                    const double tmp39 = w70*(-X_2_3 - X_2_7);
-                                    const double tmp40 = w71*(X_1_1 + X_1_3);
-                                    const double tmp41 = w72*(-X_0_2 - X_0_3);
-                                    const double tmp42 = w66*(-X_2_1 - X_2_5);
-                                    const double tmp43 = w64*(-X_0_4 - X_0_5);
-                                    const double tmp44 = w68*(-X_2_0 - X_2_3 - X_2_4 - X_2_7);
-                                    const double tmp45 = w65*(X_1_5 + X_1_7);
-                                    const double tmp46 = w70*(-X_2_2 - X_2_6);
-                                    const double tmp47 = w71*(X_1_0 + X_1_2);
-                                    const double tmp48 = w72*(X_0_0 + X_0_1);
-                                    const double tmp49 = w66*(-X_2_2 - X_2_6);
-                                    const double tmp50 = w64*(X_0_6 + X_0_7);
-                                    const double tmp51 = w65*(-X_1_4 - X_1_6);
-                                    const double tmp52 = w70*(-X_2_1 - X_2_5);
-                                    const double tmp53 = w71*(-X_1_1 - X_1_3);
-                                    const double tmp54 = w72*(-X_0_0 - X_0_1);
-                                    const double tmp55 = w66*(-X_2_3 - X_2_7);
-                                    const double tmp56 = w64*(-X_0_6 - X_0_7);
-                                    const double tmp57 = w65*(-X_1_5 - X_1_7);
-                                    const double tmp58 = w70*(-X_2_0 - X_2_4);
-                                    const double tmp59 = w71*(-X_1_0 - X_1_2);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8;
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp9;
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp12 + tmp18 + tmp19 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp26 + tmp27 + tmp28 + tmp29 + tmp3 + tmp30 + tmp31 + tmp32 + tmp33;
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp15 + tmp25 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39 + tmp40;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp33 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp6;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp31 + tmp44 + tmp48 + tmp49 + tmp50 + tmp51 + tmp52 + tmp53 + tmp8;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp17 + tmp23 + tmp37 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
-                                }
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                const double y_0 = y_p[0];
+                                const double y_1 = y_p[1];
+                                const double y_2 = y_p[2];
+                                const double y_3 = y_p[3];
+                                const double tmp0 = 6*w12*(y_1 + y_2);
+                                const double tmp1 = 6*w12*(y_0 + y_3);
+                                EM_F[0] = tmp0 + 6*w10*y_3 + 6*w11*y_0;
+                                EM_F[1] = tmp1 + 6*w10*y_2 + 6*w11*y_1;
+                                EM_F[2] = tmp1 + 6*w10*y_1 + 6*w11*y_2;
+                                EM_F[3] = tmp0 + 6*w10*y_0 + 6*w11*y_3;
+                            } else { // constant data
+                                EM_F[0] = 36*w12*y_p[0];
+                                EM_F[1] = 36*w12*y_p[0];
+                                EM_F[2] = 36*w12*y_p[0];
+                                EM_F[3] = 36*w12*y_p[0];
+                            }
+                        }
+                        const index_t firstNode=m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k1 loop
+            } // colouring
+        } // face 4
+
+        if (domain->m_faceOffset[5] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[0] = 0;
+                EM_F[1] = 0;
+                EM_F[2] = 0;
+                EM_F[3] = 0;
+            }
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
+                        ///////////////
+                        // process d //
+                        ///////////////
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            if (d.actsExpanded()) {
+                                const double d_0 = d_p[0];
+                                const double d_1 = d_p[1];
+                                const double d_2 = d_p[2];
+                                const double d_3 = d_p[3];
+                                const double tmp0 = w12*(d_0 + d_1 + d_2 + d_3);
+                                const double tmp1 = w10*(d_1 + d_3);
+                                const double tmp2 = w11*(d_0 + d_2);
+                                const double tmp3 = w10*(d_2 + d_3);
+                                const double tmp4 = w11*(d_0 + d_1);
+                                const double tmp5 = w10*(d_0 + d_1);
+                                const double tmp6 = w11*(d_2 + d_3);
+                                const double tmp7 = w12*(d_1 + d_2);
+                                const double tmp8 = w10*(d_0 + d_2);
+                                const double tmp9 = w11*(d_1 + d_3);
+                                const double tmp10 = w12*(d_0 + d_3);
+                                EM_S[INDEX2(4,4,8)] = d_0*w14 + d_3*w13 + tmp7;
+                                EM_S[INDEX2(5,4,8)] = tmp3 + tmp4;
+                                EM_S[INDEX2(6,4,8)] = tmp1 + tmp2;
+                                EM_S[INDEX2(7,4,8)] = tmp0;
+                                EM_S[INDEX2(4,5,8)] = tmp3 + tmp4;
+                                EM_S[INDEX2(5,5,8)] = d_1*w14 + d_2*w13 + tmp10;
+                                EM_S[INDEX2(6,5,8)] = tmp0;
+                                EM_S[INDEX2(7,5,8)] = tmp8 + tmp9;
+                                EM_S[INDEX2(4,6,8)] = tmp1 + tmp2;
+                                EM_S[INDEX2(5,6,8)] = tmp0;
+                                EM_S[INDEX2(6,6,8)] = d_1*w13 + d_2*w14 + tmp10;
+                                EM_S[INDEX2(7,6,8)] = tmp5 + tmp6;
+                                EM_S[INDEX2(4,7,8)] = tmp0;
+                                EM_S[INDEX2(5,7,8)] = tmp8 + tmp9;
+                                EM_S[INDEX2(6,7,8)] = tmp5 + tmp6;
+                                EM_S[INDEX2(7,7,8)] = d_0*w13 + d_3*w14 + tmp7;
                             } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double wX0 = 18*X_p[INDEX2(k, 0, numEq)]*w55;
-                                    const double wX1 = 18*X_p[INDEX2(k, 1, numEq)]*w56;
-                                    const double wX2 = 18*X_p[INDEX2(k, 2, numEq)]*w54;
-                                    EM_F[INDEX2(k,0,numEq)]+= wX0 + wX1 + wX2;
-                                    EM_F[INDEX2(k,1,numEq)]+=-wX0 + wX1 + wX2;
-                                    EM_F[INDEX2(k,2,numEq)]+= wX0 - wX1 + wX2;
-                                    EM_F[INDEX2(k,3,numEq)]+=-wX0 - wX1 + wX2;
-                                    EM_F[INDEX2(k,4,numEq)]+= wX0 + wX1 - wX2;
-                                    EM_F[INDEX2(k,5,numEq)]+=-wX0 + wX1 - wX2;
-                                    EM_F[INDEX2(k,6,numEq)]+= wX0 - wX1 - wX2;
-                                    EM_F[INDEX2(k,7,numEq)]+=-wX0 - wX1 - wX2;
-                                }
+                                const double wd0 = 4*d_p[0]*w12;
+                                EM_S[INDEX2(4,4,8)] = 4*wd0;
+                                EM_S[INDEX2(5,4,8)] = 2*wd0;
+                                EM_S[INDEX2(6,4,8)] = 2*wd0;
+                                EM_S[INDEX2(7,4,8)] =   wd0;
+                                EM_S[INDEX2(4,5,8)] = 2*wd0;
+                                EM_S[INDEX2(5,5,8)] = 4*wd0;
+                                EM_S[INDEX2(6,5,8)] =   wd0;
+                                EM_S[INDEX2(7,5,8)] = 2*wd0;
+                                EM_S[INDEX2(4,6,8)] = 2*wd0;
+                                EM_S[INDEX2(5,6,8)] =   wd0;
+                                EM_S[INDEX2(6,6,8)] = 4*wd0;
+                                EM_S[INDEX2(7,6,8)] = 2*wd0;
+                                EM_S[INDEX2(4,7,8)] =   wd0;
+                                EM_S[INDEX2(5,7,8)] = 2*wd0;
+                                EM_S[INDEX2(6,7,8)] = 2*wd0;
+                                EM_S[INDEX2(7,7,8)] = 4*wd0;
                             }
                         }
                         ///////////////
-                        // process Y //
+                        // process y //
                         ///////////////
-                        if (!Y.isEmpty()) {
-                            add_EM_F=true;
-                            const double* Y_p=Y.getSampleDataRO(e);
-                            if (Y.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double Y_0 = Y_p[INDEX2(k, 0, numEq)];
-                                    const double Y_1 = Y_p[INDEX2(k, 1, numEq)];
-                                    const double Y_2 = Y_p[INDEX2(k, 2, numEq)];
-                                    const double Y_3 = Y_p[INDEX2(k, 3, numEq)];
-                                    const double Y_4 = Y_p[INDEX2(k, 4, numEq)];
-                                    const double Y_5 = Y_p[INDEX2(k, 5, numEq)];
-                                    const double Y_6 = Y_p[INDEX2(k, 6, numEq)];
-                                    const double Y_7 = Y_p[INDEX2(k, 7, numEq)];
-                                    const double tmp0 = w76*(Y_3 + Y_5 + Y_6);
-                                    const double tmp1 = w75*(Y_1 + Y_2 + Y_4);
-                                    const double tmp2 = w76*(Y_2 + Y_4 + Y_7);
-                                    const double tmp3 = w75*(Y_0 + Y_3 + Y_5);
-                                    const double tmp4 = w76*(Y_1 + Y_4 + Y_7);
-                                    const double tmp5 = w75*(Y_0 + Y_3 + Y_6);
-                                    const double tmp6 = w76*(Y_0 + Y_5 + Y_6);
-                                    const double tmp7 = w75*(Y_1 + Y_2 + Y_7);
-                                    const double tmp8 = w76*(Y_1 + Y_2 + Y_7);
-                                    const double tmp9 = w75*(Y_0 + Y_5 + Y_6);
-                                    const double tmp10 = w76*(Y_0 + Y_3 + Y_6);
-                                    const double tmp11 = w75*(Y_1 + Y_4 + Y_7);
-                                    const double tmp12 = w76*(Y_0 + Y_3 + Y_5);
-                                    const double tmp13 = w75*(Y_2 + Y_4 + Y_7);
-                                    const double tmp14 = w76*(Y_1 + Y_2 + Y_4);
-                                    const double tmp15 = w75*(Y_3 + Y_5 + Y_6);
-                                    EM_F[INDEX2(k,0,numEq)]+=Y_0*w74 + Y_7*w77 + tmp0 + tmp1;
-                                    EM_F[INDEX2(k,1,numEq)]+=Y_1*w74 + Y_6*w77 + tmp2 + tmp3;
-                                    EM_F[INDEX2(k,2,numEq)]+=Y_2*w74 + Y_5*w77 + tmp4 + tmp5;
-                                    EM_F[INDEX2(k,3,numEq)]+=Y_3*w74 + Y_4*w77 + tmp6 + tmp7;
-                                    EM_F[INDEX2(k,4,numEq)]+=Y_3*w77 + Y_4*w74 + tmp8 + tmp9;
-                                    EM_F[INDEX2(k,5,numEq)]+=Y_2*w77 + Y_5*w74 + tmp10 + tmp11;
-                                    EM_F[INDEX2(k,6,numEq)]+=Y_1*w77 + Y_6*w74 + tmp12 + tmp13;
-                                    EM_F[INDEX2(k,7,numEq)]+=Y_0*w77 + Y_7*w74 + tmp14 + tmp15;
-                                }
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                const double y_0 = y_p[0];
+                                const double y_1 = y_p[1];
+                                const double y_2 = y_p[2];
+                                const double y_3 = y_p[3];
+                                const double tmp0 = 6*w12*(y_1 + y_2);
+                                const double tmp1 = 6*w12*(y_0 + y_3);
+                                EM_F[4] = tmp0 + 6*w10*y_3 + 6*w11*y_0;
+                                EM_F[5] = tmp1 + 6*w10*y_2 + 6*w11*y_1;
+                                EM_F[6] = tmp1 + 6*w10*y_1 + 6*w11*y_2;
+                                EM_F[7] = tmp0 + 6*w10*y_0 + 6*w11*y_3;
                             } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,1,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,2,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,3,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,4,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,5,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,6,numEq)]+=216*Y_p[k]*w58;
-                                    EM_F[INDEX2(k,7,numEq)]+=216*Y_p[k]*w58;
-                                }
+                                EM_F[4] = 36*w12*y_p[0];
+                                EM_F[5] = 36*w12*y_p[0];
+                                EM_F[6] = 36*w12*y_p[0];
+                                EM_F[7] = 36*w12*y_p[0];
                             }
                         }
-
-                        // add to matrix (if add_EM_S) and RHS (if add_EM_F)
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // end k0 loop
-                } // end k1 loop
-            } // end k2 loop
-        } // end of colouring
+                        const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k1 loop
+            } // colouring
+        } // face 5
     } // end of parallel region
 }
 
-//protected
-void DefaultAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
-                                     Data& rhs, const Data& A, const Data& B,
-                                     const Data& C, const Data& D,
-                                     const Data& X, const Data& Y) const
-{
-    dim_t numEq, numComp;
-    if (!mat)
-        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
-    else {
-        numEq=mat->getRowBlockSize();
-        numComp=mat->getColumnBlockSize();
-    }
+/****************************************************************************/
+// PDE SINGLE REDUCED
+/****************************************************************************/
 
-    const double w0 = m_dx[0]/16;
-    const double w1 = m_dx[1]/16;
-    const double w2 = m_dx[2]/16;
-    const double w3 = m_dx[0]*m_dx[1]/32;
-    const double w4 = m_dx[0]*m_dx[2]/32;
-    const double w5 = m_dx[1]*m_dx[2]/32;
-    const double w6 = m_dx[0]*m_dx[1]/(16*m_dx[2]);
-    const double w7 = m_dx[0]*m_dx[2]/(16*m_dx[1]);
-    const double w8 = m_dx[1]*m_dx[2]/(16*m_dx[0]);
-    const double w9 = m_dx[0]*m_dx[1]*m_dx[2]/64;
+void DefaultAssembler3D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
+                                    Data& rhs, const Data& A, const Data& B,
+                                    const Data& C, const Data& D,
+                                    const Data& X, const Data& Y) const
+{
+    const double w6 = m_dx[0]/16;
+    const double w5 = m_dx[1]/16;
+    const double w1 = m_dx[2]/16;
+    const double w14 = m_dx[0]*m_dx[1]/32;
+    const double w13 = m_dx[0]*m_dx[2]/32;
+    const double w12 = m_dx[1]*m_dx[2]/32;
+    const double w18 = m_dx[0]*m_dx[1]*m_dx[2]/64;
+    const double w11 = m_dx[0]*m_dx[1]/(16*m_dx[2]);
+    const double w3 = m_dx[0]*m_dx[2]/(16*m_dx[1]);
+    const double w0 = m_dx[1]*m_dx[2]/(16*m_dx[0]);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
+    const bool add_EM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool add_EM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8, 0);
+        vector<double> EM_F(8, 0);
+
         for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
             for (index_t k2=k2_0; k2<NE2; k2+=2) {
                 for (index_t k1=0; k1<NE1; ++k1) {
                     for (index_t k0=0; k0<NE0; ++k0)  {
-                        bool add_EM_S=false;
-                        bool add_EM_F=false;
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                        if (add_EM_S)
+                            fill(EM_S.begin(), EM_S.end(), 0);
+                        if (add_EM_F)
+                            fill(EM_F.begin(), EM_F.end(), 0);
+
                         ///////////////
                         // process A //
                         ///////////////
                         if (!A.isEmpty()) {
-                            add_EM_S=true;
                             const double* A_p=A.getSampleDataRO(e);
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double Aw00 = A_p[INDEX4(k,0,m,0,numEq,3,numComp)]*w8;
-                                    const double Aw10 = A_p[INDEX4(k,1,m,0,numEq,3,numComp)]*w2;
-                                    const double Aw20 = A_p[INDEX4(k,2,m,0,numEq,3,numComp)]*w1;
-                                    const double Aw01 = A_p[INDEX4(k,0,m,1,numEq,3,numComp)]*w2;
-                                    const double Aw11 = A_p[INDEX4(k,1,m,1,numEq,3,numComp)]*w7;
-                                    const double Aw21 = A_p[INDEX4(k,2,m,1,numEq,3,numComp)]*w0;
-                                    const double Aw02 = A_p[INDEX4(k,0,m,2,numEq,3,numComp)]*w1;
-                                    const double Aw12 = A_p[INDEX4(k,1,m,2,numEq,3,numComp)]*w0;
-                                    const double Aw22 = A_p[INDEX4(k,2,m,2,numEq,3,numComp)]*w6;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
-                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
-                                }
-                            }
+                            const double Aw00 = A_p[INDEX2(0,0,3)]*w0;
+                            const double Aw10 = A_p[INDEX2(1,0,3)]*w1;
+                            const double Aw20 = A_p[INDEX2(2,0,3)]*w5;
+                            const double Aw01 = A_p[INDEX2(0,1,3)]*w1;
+                            const double Aw11 = A_p[INDEX2(1,1,3)]*w3;
+                            const double Aw21 = A_p[INDEX2(2,1,3)]*w6;
+                            const double Aw02 = A_p[INDEX2(0,2,3)]*w5;
+                            const double Aw12 = A_p[INDEX2(1,2,3)]*w6;
+                            const double Aw22 = A_p[INDEX2(2,2,3)]*w11;
+                            EM_S[INDEX2(0,0,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(1,0,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(2,0,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(3,0,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(4,0,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(5,0,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(6,0,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(7,0,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(0,1,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(1,1,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(2,1,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(3,1,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(4,1,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(5,1,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(6,1,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(7,1,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(0,2,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(1,2,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(2,2,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(3,2,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(4,2,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(5,2,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(6,2,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(7,2,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(0,3,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(1,3,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(2,3,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(3,3,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(4,3,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(5,3,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(6,3,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(7,3,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(0,4,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(1,4,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(2,4,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(3,4,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(4,4,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(5,4,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(6,4,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(7,4,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(0,5,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(1,5,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(2,5,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(3,5,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                            EM_S[INDEX2(4,5,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(5,5,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(6,5,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(7,5,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                            EM_S[INDEX2(0,6,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(1,6,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(2,6,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(3,6,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(4,6,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(5,6,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(6,6,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(7,6,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(0,7,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(1,7,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(2,7,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(3,7,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                            EM_S[INDEX2(4,7,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(5,7,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(6,7,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                            EM_S[INDEX2(7,7,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
                         }
                         ///////////////
                         // process B //
                         ///////////////
                         if (!B.isEmpty()) {
-                            add_EM_S=true;
                             const double* B_p=B.getSampleDataRO(e);
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double wB0 = B_p[INDEX3(k,0,m, numEq, 3)]*w5;
-                                    const double wB1 = B_p[INDEX3(k,1,m, numEq, 3)]*w4;
-                                    const double wB2 = B_p[INDEX3(k,2,m, numEq, 3)]*w3;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+= wB0 - wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+= wB0 + wB1 - wB2;
-                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+= wB0 - wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+= wB0 + wB1 + wB2;
-                                }
-                            }
+                            const double wB0 = B_p[0]*w12;
+                            const double wB1 = B_p[1]*w13;
+                            const double wB2 = B_p[2]*w14;
+                            EM_S[INDEX2(0,0,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,0,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,0,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,0,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,0,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,0,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,0,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,0,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,1,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,1,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,1,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,1,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,1,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,1,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,1,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,1,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,2,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,2,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,2,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,2,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,2,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,2,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,2,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,2,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,3,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,3,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,3,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,3,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,3,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,3,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,3,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,3,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,4,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,4,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,4,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,4,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,4,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,4,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,4,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,4,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,5,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,5,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,5,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,5,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,5,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,5,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,5,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,5,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,6,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,6,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,6,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,6,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,6,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,6,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,6,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,6,8)]+= wB0 + wB1 + wB2;
+                            EM_S[INDEX2(0,7,8)]+=-wB0 - wB1 - wB2;
+                            EM_S[INDEX2(1,7,8)]+= wB0 - wB1 - wB2;
+                            EM_S[INDEX2(2,7,8)]+=-wB0 + wB1 - wB2;
+                            EM_S[INDEX2(3,7,8)]+= wB0 + wB1 - wB2;
+                            EM_S[INDEX2(4,7,8)]+=-wB0 - wB1 + wB2;
+                            EM_S[INDEX2(5,7,8)]+= wB0 - wB1 + wB2;
+                            EM_S[INDEX2(6,7,8)]+=-wB0 + wB1 + wB2;
+                            EM_S[INDEX2(7,7,8)]+= wB0 + wB1 + wB2;
                         }
                         ///////////////
                         // process C //
                         ///////////////
                         if (!C.isEmpty()) {
-                            add_EM_S=true;
                             const double* C_p=C.getSampleDataRO(e);
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double wC0 = C_p[INDEX3(k, m, 0, numEq, numComp)]*w5;
-                                    const double wC1 = C_p[INDEX3(k, m, 1, numEq, numComp)]*w4;
-                                    const double wC2 = C_p[INDEX3(k, m, 2, numEq, numComp)]*w3;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
-                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
-                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
-                                }
-                            }
+                            const double wC0 = C_p[0]*w12;
+                            const double wC1 = C_p[1]*w13;
+                            const double wC2 = C_p[2]*w14;
+                            EM_S[INDEX2(0,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(1,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(2,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(3,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(4,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(5,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(6,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(7,0,8)]+=-wC0 - wC1 - wC2;
+                            EM_S[INDEX2(0,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(1,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(2,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(3,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(4,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(5,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(6,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(7,1,8)]+= wC0 - wC1 - wC2;
+                            EM_S[INDEX2(0,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(1,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(2,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(3,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(4,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(5,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(6,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(7,2,8)]+=-wC0 + wC1 - wC2;
+                            EM_S[INDEX2(0,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(1,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(2,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(3,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(4,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(5,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(6,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(7,3,8)]+= wC0 + wC1 - wC2;
+                            EM_S[INDEX2(0,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(1,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(2,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(3,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(4,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(5,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(6,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(7,4,8)]+=-wC0 - wC1 + wC2;
+                            EM_S[INDEX2(0,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(1,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(2,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(3,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(4,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(5,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(6,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(7,5,8)]+= wC0 - wC1 + wC2;
+                            EM_S[INDEX2(0,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(1,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(2,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(3,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(4,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(5,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(6,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(7,6,8)]+=-wC0 + wC1 + wC2;
+                            EM_S[INDEX2(0,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(1,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(2,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(3,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(4,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(5,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(6,7,8)]+= wC0 + wC1 + wC2;
+                            EM_S[INDEX2(7,7,8)]+= wC0 + wC1 + wC2;
                         }
                         ///////////////
                         // process D //
                         ///////////////
                         if (!D.isEmpty()) {
-                            add_EM_S=true;
                             const double* D_p=D.getSampleDataRO(e);
-                            for (index_t k=0; k<numEq; k++) {
-                                for (index_t m=0; m<numComp; m++) {
-                                    const double wD = D_p[INDEX2(k, m, numEq)]*w9;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=wD;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=wD;
-                                }
-                            }
+                            EM_S[INDEX2(0,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,0,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,1,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,2,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,3,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,4,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,5,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,6,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(0,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(1,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(2,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(3,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(4,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(5,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(6,7,8)]+=D_p[0]*w18;
+                            EM_S[INDEX2(7,7,8)]+=D_p[0]*w18;
                         }
                         ///////////////
                         // process X //
                         ///////////////
                         if (!X.isEmpty()) {
-                            add_EM_F=true;
                             const double* X_p=X.getSampleDataRO(e);
-                            for (index_t k=0; k<numEq; k++) {
-                                const double wX0 = 8*X_p[INDEX2(k, 0, numEq)]*w5;
-                                const double wX1 = 8*X_p[INDEX2(k, 1, numEq)]*w4;
-                                const double wX2 = 8*X_p[INDEX2(k, 2, numEq)]*w3;
-                                EM_F[INDEX2(k,0,numEq)]+=-wX0 - wX1 - wX2;
-                                EM_F[INDEX2(k,1,numEq)]+= wX0 - wX1 - wX2;
-                                EM_F[INDEX2(k,2,numEq)]+=-wX0 + wX1 - wX2;
-                                EM_F[INDEX2(k,3,numEq)]+= wX0 + wX1 - wX2;
-                                EM_F[INDEX2(k,4,numEq)]+=-wX0 - wX1 + wX2;
-                                EM_F[INDEX2(k,5,numEq)]+= wX0 - wX1 + wX2;
-                                EM_F[INDEX2(k,6,numEq)]+=-wX0 + wX1 + wX2;
-                                EM_F[INDEX2(k,7,numEq)]+= wX0 + wX1 + wX2;
-                            }
+                            const double wX0 = 8*X_p[0]*w12;
+                            const double wX1 = 8*X_p[1]*w13;
+                            const double wX2 = 8*X_p[2]*w14;
+                            EM_F[0]+=-wX0 - wX1 - wX2;
+                            EM_F[1]+= wX0 - wX1 - wX2;
+                            EM_F[2]+=-wX0 + wX1 - wX2;
+                            EM_F[3]+= wX0 + wX1 - wX2;
+                            EM_F[4]+=-wX0 - wX1 + wX2;
+                            EM_F[5]+= wX0 - wX1 + wX2;
+                            EM_F[6]+=-wX0 + wX1 + wX2;
+                            EM_F[7]+= wX0 + wX1 + wX2;
                         }
                         ///////////////
                         // process Y //
                         ///////////////
                         if (!Y.isEmpty()) {
-                            add_EM_F=true;
                             const double* Y_p=Y.getSampleDataRO(e);
-                            for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,1,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,2,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,3,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,4,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,5,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,6,numEq)]+=8*Y_p[k]*w9;
-                                EM_F[INDEX2(k,7,numEq)]+=8*Y_p[k]*w9;
-                            }
+                            EM_F[0]+=8*Y_p[0]*w18;
+                            EM_F[1]+=8*Y_p[0]*w18;
+                            EM_F[2]+=8*Y_p[0]*w18;
+                            EM_F[3]+=8*Y_p[0]*w18;
+                            EM_F[4]+=8*Y_p[0]*w18;
+                            EM_F[5]+=8*Y_p[0]*w18;
+                            EM_F[6]+=8*Y_p[0]*w18;
+                            EM_F[7]+=8*Y_p[0]*w18;
                         }
 
                         // add to matrix (if add_EM_S) and RHS (if add_EM_F)
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
                     } // end k0 loop
                 } // end k1 loop
             } // end k2 loop
@@ -5099,964 +3244,2867 @@ void DefaultAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
     } // end of parallel region
 }
 
-//protected
-void DefaultAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
-                                Data& rhs, const Data& d, const Data& y) const
+/****************************************************************************/
+// PDE SINGLE REDUCED BOUNDARY
+/****************************************************************************/
+
+void DefaultAssembler3D::assemblePDEBoundarySingleReduced(
+                                        AbstractSystemMatrix* mat, Data& rhs,
+                                        const Data& d, const Data& y) const
 {
-    const double SQRT3 = 1.73205080756887719318;
-    const double w12 = m_dx[0]*m_dx[1]/144;
-    const double w10 = w12*(-SQRT3 + 2);
-    const double w11 = w12*(SQRT3 + 2);
-    const double w13 = w12*(-4*SQRT3 + 7);
-    const double w14 = w12*(4*SQRT3 + 7);
-    const double w7 = m_dx[0]*m_dx[2]/144;
-    const double w5 = w7*(-SQRT3 + 2);
-    const double w6 = w7*(SQRT3 + 2);
-    const double w8 = w7*(-4*SQRT3 + 7);
-    const double w9 = w7*(4*SQRT3 + 7);
-    const double w2 = m_dx[1]*m_dx[2]/144;
-    const double w0 = w2*(-SQRT3 + 2);
-    const double w1 = w2*(SQRT3 + 2);
-    const double w3 = w2*(-4*SQRT3 + 7);
-    const double w4 = w2*(4*SQRT3 + 7);
-    const bool add_EM_S=!d.isEmpty();
-    const bool add_EM_F=!y.isEmpty();
+    const double w0 = m_dx[0]*m_dx[1]/16;
+    const double w1 = m_dx[0]*m_dx[2]/16;
+    const double w2 = m_dx[1]*m_dx[2]/16;
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
+    const bool add_EM_S = !d.isEmpty();
+    const bool add_EM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8);
+        vector<double> EM_F(8);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[1] = 0;
+                EM_F[3] = 0;
+                EM_F[5] = 0;
+                EM_F[7] = 0;
+            }
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = INDEX2(k1,k2,NE1);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                const double d_0 = d_p[0];
-                                const double d_1 = d_p[1];
-                                const double d_2 = d_p[2];
-                                const double d_3 = d_p[3];
-                                const double tmp0 = w0*(d_0 + d_1);
-                                const double tmp1 = w1*(d_2 + d_3);
-                                const double tmp2 = w0*(d_0 + d_2);
-                                const double tmp3 = w1*(d_1 + d_3);
-                                const double tmp4 = w0*(d_1 + d_3);
-                                const double tmp5 = w1*(d_0 + d_2);
-                                const double tmp6 = w0*(d_2 + d_3);
-                                const double tmp7 = w1*(d_0 + d_1);
-                                const double tmp8 = w2*(d_0 + d_3);
-                                const double tmp9 = w2*(d_1 + d_2);
-                                const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
-                                EM_S[INDEX2(0,0,8)]+=d_0*w4 + d_3*w3 + tmp9;
-                                EM_S[INDEX2(0,2,8)]+=tmp6 + tmp7;
-                                EM_S[INDEX2(0,4,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(0,6,8)]+=tmp10;
-                                EM_S[INDEX2(2,0,8)]+=tmp6 + tmp7;
-                                EM_S[INDEX2(2,2,8)]+=d_1*w4 + d_2*w3 + tmp8;
-                                EM_S[INDEX2(2,4,8)]+=tmp10;
-                                EM_S[INDEX2(2,6,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(4,0,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(4,2,8)]+=tmp10;
-                                EM_S[INDEX2(4,4,8)]+=d_1*w3 + d_2*w4 + tmp8;
-                                EM_S[INDEX2(4,6,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(6,0,8)]+=tmp10;
-                                EM_S[INDEX2(6,2,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(6,4,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(6,6,8)]+=d_0*w3 + d_3*w4 + tmp9;
-                            } else { // constant data
-                                const double wd0 = 4*d_p[0]*w2;
-                                EM_S[INDEX2(0,0,8)]+=4*wd0;
-                                EM_S[INDEX2(0,2,8)]+=2*wd0;
-                                EM_S[INDEX2(0,4,8)]+=2*wd0;
-                                EM_S[INDEX2(0,6,8)]+=  wd0;
-                                EM_S[INDEX2(2,0,8)]+=2*wd0;
-                                EM_S[INDEX2(2,2,8)]+=4*wd0;
-                                EM_S[INDEX2(2,4,8)]+=  wd0;
-                                EM_S[INDEX2(2,6,8)]+=2*wd0;
-                                EM_S[INDEX2(4,0,8)]+=2*wd0;
-                                EM_S[INDEX2(4,2,8)]+=  wd0;
-                                EM_S[INDEX2(4,4,8)]+=4*wd0;
-                                EM_S[INDEX2(4,6,8)]+=2*wd0;
-                                EM_S[INDEX2(6,0,8)]+=  wd0;
-                                EM_S[INDEX2(6,2,8)]+=2*wd0;
-                                EM_S[INDEX2(6,4,8)]+=2*wd0;
-                                EM_S[INDEX2(6,6,8)]+=4*wd0;
-                            }
+                            EM_S[INDEX2(0,0,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(2,0,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(4,0,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(6,0,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(0,2,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(2,2,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(4,2,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(6,2,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(0,4,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(2,4,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(4,4,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(6,4,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(0,6,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(2,6,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(4,6,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(6,6,8)] = d_p[0]*w2;
                         }
                         ///////////////
                         // process y //
                         ///////////////
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                const double y_0 = y_p[0];
-                                const double y_1 = y_p[1];
-                                const double y_2 = y_p[2];
-                                const double y_3 = y_p[3];
-                                const double tmp0 = 6*w2*(y_1 + y_2);
-                                const double tmp1 = 6*w2*(y_0 + y_3);
-                                EM_F[0]+=tmp0 + 6*w0*y_3 + 6*w1*y_0;
-                                EM_F[2]+=tmp1 + 6*w0*y_2 + 6*w1*y_1;
-                                EM_F[4]+=tmp1 + 6*w0*y_1 + 6*w1*y_2;
-                                EM_F[6]+=tmp0 + 6*w0*y_0 + 6*w1*y_3;
-                            } else { // constant data
-                                EM_F[0]+=36*w2*y_p[0];
-                                EM_F[2]+=36*w2*y_p[0];
-                                EM_F[4]+=36*w2*y_p[0];
-                                EM_F[6]+=36*w2*y_p[0];
-                            }
+                            EM_F[0] = 4*w2*y_p[0];
+                            EM_F[2] = 4*w2*y_p[0];
+                            EM_F[4] = 4*w2*y_p[0];
+                            EM_F[6] = 4*w2*y_p[0];
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 0
 
         if (domain->m_faceOffset[1] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[0] = 0;
+                EM_F[2] = 0;
+                EM_F[4] = 0;
+                EM_F[6] = 0;
+            }
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = domain->m_faceOffset[1]+INDEX2(k1,k2,NE1);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                const double d_0 = d_p[0];
-                                const double d_1 = d_p[1];
-                                const double d_2 = d_p[2];
-                                const double d_3 = d_p[3];
-                                const double tmp0 = w0*(d_0 + d_2);
-                                const double tmp1 = w1*(d_1 + d_3);
-                                const double tmp2 = w0*(d_2 + d_3);
-                                const double tmp3 = w1*(d_0 + d_1);
-                                const double tmp4 = w0*(d_1 + d_3);
-                                const double tmp5 = w1*(d_0 + d_2);
-                                const double tmp6 = w2*(d_0 + d_3);
-                                const double tmp7 = w2*(d_1 + d_2);
-                                const double tmp8 = w0*(d_0 + d_1);
-                                const double tmp9 = w1*(d_2 + d_3);
-                                const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
-                                EM_S[INDEX2(1,1,8)]+=d_0*w4 + d_3*w3 + tmp7;
-                                EM_S[INDEX2(1,3,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(1,5,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(1,7,8)]+=tmp10;
-                                EM_S[INDEX2(3,1,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(3,3,8)]+=d_1*w4 + d_2*w3 + tmp6;
-                                EM_S[INDEX2(3,5,8)]+=tmp10;
-                                EM_S[INDEX2(3,7,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(5,1,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(5,3,8)]+=tmp10;
-                                EM_S[INDEX2(5,5,8)]+=d_1*w3 + d_2*w4 + tmp6;
-                                EM_S[INDEX2(5,7,8)]+=tmp8 + tmp9;
-                                EM_S[INDEX2(7,1,8)]+=tmp10;
-                                EM_S[INDEX2(7,3,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(7,5,8)]+=tmp8 + tmp9;
-                                EM_S[INDEX2(7,7,8)]+=d_0*w3 + d_3*w4 + tmp7;
-                            } else { // constant data
-                                const double wd0 = 4*d_p[0]*w2;
-                                EM_S[INDEX2(1,1,8)]+=4*wd0;
-                                EM_S[INDEX2(1,3,8)]+=2*wd0;
-                                EM_S[INDEX2(1,5,8)]+=2*wd0;
-                                EM_S[INDEX2(1,7,8)]+=  wd0;
-                                EM_S[INDEX2(3,1,8)]+=2*wd0;
-                                EM_S[INDEX2(3,3,8)]+=4*wd0;
-                                EM_S[INDEX2(3,5,8)]+=  wd0;
-                                EM_S[INDEX2(3,7,8)]+=2*wd0;
-                                EM_S[INDEX2(5,1,8)]+=2*wd0;
-                                EM_S[INDEX2(5,3,8)]+=  wd0;
-                                EM_S[INDEX2(5,5,8)]+=4*wd0;
-                                EM_S[INDEX2(5,7,8)]+=2*wd0;
-                                EM_S[INDEX2(7,1,8)]+=  wd0;
-                                EM_S[INDEX2(7,3,8)]+=2*wd0;
-                                EM_S[INDEX2(7,5,8)]+=2*wd0;
-                                EM_S[INDEX2(7,7,8)]+=4*wd0;
-                            }
+                            EM_S[INDEX2(1,1,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(3,1,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(5,1,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(7,1,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(1,3,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(3,3,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(5,3,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(7,3,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(1,5,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(3,5,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(5,5,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(7,5,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(1,7,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(3,7,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(5,7,8)] = d_p[0]*w2;
+                            EM_S[INDEX2(7,7,8)] = d_p[0]*w2;
                         }
                         ///////////////
                         // process y //
                         ///////////////
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                const double y_0 = y_p[0];
-                                const double y_1 = y_p[1];
-                                const double y_2 = y_p[2];
-                                const double y_3 = y_p[3];
-                                const double tmp0 = 6*w2*(y_1 + y_2);
-                                const double tmp1 = 6*w2*(y_0 + y_3);
-                                EM_F[1]+=tmp0 + 6*w0*y_3 + 6*w1*y_0;
-                                EM_F[3]+=tmp1 + 6*w0*y_2 + 6*w1*y_1;
-                                EM_F[5]+=tmp1 + 6*w0*y_1 + 6*w1*y_2;
-                                EM_F[7]+=tmp0 + 6*w0*y_0 + 6*w1*y_3;
-                            } else { // constant data
-                                EM_F[1]+=36*w2*y_p[0];
-                                EM_F[3]+=36*w2*y_p[0];
-                                EM_F[5]+=36*w2*y_p[0];
-                                EM_F[7]+=36*w2*y_p[0];
-                            }
+                            EM_F[1] = 4*w2*y_p[0];
+                            EM_F[3] = 4*w2*y_p[0];
+                            EM_F[5] = 4*w2*y_p[0];
+                            EM_F[7] = 4*w2*y_p[0];
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(k1+1)-2;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 1
 
         if (domain->m_faceOffset[2] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[2] = 0;
+                EM_F[3] = 0;
+                EM_F[6] = 0;
+                EM_F[7] = 0;
+            }
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,NE0);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                const double d_0 = d_p[0];
-                                const double d_1 = d_p[1];
-                                const double d_2 = d_p[2];
-                                const double d_3 = d_p[3];
-                                const double tmp0 = w5*(d_0 + d_1);
-                                const double tmp1 = w6*(d_2 + d_3);
-                                const double tmp2 = w5*(d_0 + d_2);
-                                const double tmp3 = w6*(d_1 + d_3);
-                                const double tmp4 = w5*(d_1 + d_3);
-                                const double tmp5 = w6*(d_0 + d_2);
-                                const double tmp6 = w7*(d_0 + d_3);
-                                const double tmp7 = w7*(d_0 + d_1 + d_2 + d_3);
-                                const double tmp8 = w7*(d_1 + d_2);
-                                const double tmp9 = w5*(d_2 + d_3);
-                                const double tmp10 = w6*(d_0 + d_1);
-                                EM_S[INDEX2(0,0,8)]+=d_0*w9 + d_3*w8 + tmp8;
-                                EM_S[INDEX2(0,1,8)]+=tmp10 + tmp9;
-                                EM_S[INDEX2(0,4,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(0,5,8)]+=tmp7;
-                                EM_S[INDEX2(1,0,8)]+=tmp10 + tmp9;
-                                EM_S[INDEX2(1,1,8)]+=d_1*w9 + d_2*w8 + tmp6;
-                                EM_S[INDEX2(1,4,8)]+=tmp7;
-                                EM_S[INDEX2(1,5,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(4,0,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(4,1,8)]+=tmp7;
-                                EM_S[INDEX2(4,4,8)]+=d_1*w8 + d_2*w9 + tmp6;
-                                EM_S[INDEX2(4,5,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(5,0,8)]+=tmp7;
-                                EM_S[INDEX2(5,1,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(5,4,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(5,5,8)]+=d_0*w8 + d_3*w9 + tmp8;
-                            } else { // constant data
-                                const double wd0 = 4*d_p[0]*w7;
-                                EM_S[INDEX2(0,0,8)]+=4*wd0;
-                                EM_S[INDEX2(0,1,8)]+=2*wd0;
-                                EM_S[INDEX2(0,4,8)]+=2*wd0;
-                                EM_S[INDEX2(0,5,8)]+=  wd0;
-                                EM_S[INDEX2(1,0,8)]+=2*wd0;
-                                EM_S[INDEX2(1,1,8)]+=4*wd0;
-                                EM_S[INDEX2(1,4,8)]+=  wd0;
-                                EM_S[INDEX2(1,5,8)]+=2*wd0;
-                                EM_S[INDEX2(4,0,8)]+=2*wd0;
-                                EM_S[INDEX2(4,1,8)]+=  wd0;
-                                EM_S[INDEX2(4,4,8)]+=4*wd0;
-                                EM_S[INDEX2(4,5,8)]+=2*wd0;
-                                EM_S[INDEX2(5,0,8)]+=  wd0;
-                                EM_S[INDEX2(5,1,8)]+=2*wd0;
-                                EM_S[INDEX2(5,4,8)]+=2*wd0;
-                                EM_S[INDEX2(5,5,8)]+=4*wd0;
-                            }
+                            EM_S[INDEX2(0,0,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(1,0,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(4,0,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(5,0,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(0,1,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(1,1,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(4,1,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(5,1,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(0,4,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(1,4,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(4,4,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(5,4,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(0,5,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(1,5,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(4,5,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(5,5,8)] = d_p[0]*w1;
                         }
                         ///////////////
                         // process y //
                         ///////////////
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                const double y_0 = y_p[0];
-                                const double y_1 = y_p[1];
-                                const double y_2 = y_p[2];
-                                const double y_3 = y_p[3];
-                                const double tmp0 = 6*w7*(y_1 + y_2);
-                                const double tmp1 = 6*w7*(y_0 + y_3);
-                                EM_F[0]+=tmp0 + 6*w5*y_3 + 6*w6*y_0;
-                                EM_F[1]+=tmp1 + 6*w5*y_2 + 6*w6*y_1;
-                                EM_F[4]+=tmp1 + 6*w5*y_1 + 6*w6*y_2;
-                                EM_F[5]+=tmp0 + 6*w5*y_0 + 6*w6*y_3;
-                            } else { // constant data
-                                EM_F[0]+=36*w7*y_p[0];
-                                EM_F[1]+=36*w7*y_p[0];
-                                EM_F[4]+=36*w7*y_p[0];
-                                EM_F[5]+=36*w7*y_p[0];
-                            }
+                            EM_F[0] = 4*w1*y_p[0];
+                            EM_F[1] = 4*w1*y_p[0];
+                            EM_F[4] = 4*w1*y_p[0];
+                            EM_F[5] = 4*w1*y_p[0];
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
                     } // k0 loop
                 } // k2 loop
             } // colouring
         } // face 2
 
         if (domain->m_faceOffset[3] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[0] = 0;
+                EM_F[1] = 0;
+                EM_F[4] = 0;
+                EM_F[5] = 0;
+            }
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,NE0);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                const double d_0 = d_p[0];
-                                const double d_1 = d_p[1];
-                                const double d_2 = d_p[2];
-                                const double d_3 = d_p[3];
-                                const double tmp0 = w5*(d_0 + d_2);
-                                const double tmp1 = w6*(d_1 + d_3);
-                                const double tmp2 = w5*(d_1 + d_3);
-                                const double tmp3 = w6*(d_0 + d_2);
-                                const double tmp4 = w7*(d_0 + d_1 + d_2 + d_3);
-                                const double tmp5 = w5*(d_0 + d_1);
-                                const double tmp6 = w6*(d_2 + d_3);
-                                const double tmp7 = w7*(d_0 + d_3);
-                                const double tmp8 = w7*(d_1 + d_2);
-                                const double tmp9 = w5*(d_2 + d_3);
-                                const double tmp10 = w6*(d_0 + d_1);
-                                EM_S[INDEX2(2,2,8)]+=d_0*w9 + d_3*w8 + tmp8;
-                                EM_S[INDEX2(2,3,8)]+=tmp10 + tmp9;
-                                EM_S[INDEX2(2,6,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(2,7,8)]+=tmp4;
-                                EM_S[INDEX2(3,2,8)]+=tmp10 + tmp9;
-                                EM_S[INDEX2(3,3,8)]+=d_1*w9 + d_2*w8 + tmp7;
-                                EM_S[INDEX2(3,6,8)]+=tmp4;
-                                EM_S[INDEX2(3,7,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(6,2,8)]+=tmp2 + tmp3;
-                                EM_S[INDEX2(6,3,8)]+=tmp4;
-                                EM_S[INDEX2(6,6,8)]+=d_1*w8 + d_2*w9 + tmp7;
-                                EM_S[INDEX2(6,7,8)]+=tmp5 + tmp6;
-                                EM_S[INDEX2(7,2,8)]+=tmp4;
-                                EM_S[INDEX2(7,3,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(7,6,8)]+=tmp5 + tmp6;
-                                EM_S[INDEX2(7,7,8)]+=d_0*w8 + d_3*w9 + tmp8;
+                            EM_S[INDEX2(2,2,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(3,2,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(6,2,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(7,2,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(2,3,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(3,3,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(6,3,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(7,3,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(2,6,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(3,6,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(6,6,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(7,6,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(2,7,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(3,7,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(6,7,8)] = d_p[0]*w1;
+                            EM_S[INDEX2(7,7,8)] = d_p[0]*w1;
+                        }
+                        ///////////////
+                        // process y //
+                        ///////////////
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            EM_F[2] = 4*w1*y_p[0];
+                            EM_F[3] = 4*w1*y_p[0];
+                            EM_F[6] = 4*w1*y_p[0];
+                            EM_F[7] = 4*w1*y_p[0];
+                        }
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k2 loop
+            } // colouring
+        } // face 3
+
+        if (domain->m_faceOffset[4] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[4] = 0;
+                EM_F[5] = 0;
+                EM_F[6] = 0;
+                EM_F[7] = 0;
+            }
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
+                        ///////////////
+                        // process d //
+                        ///////////////
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            EM_S[INDEX2(0,0,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(1,0,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(2,0,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(3,0,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(0,1,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(1,1,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(2,1,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(3,1,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(0,2,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(1,2,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(2,2,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(3,2,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(0,3,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(1,3,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(2,3,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(3,3,8)] = d_p[0]*w0;
+                        }
+                        ///////////////
+                        // process y //
+                        ///////////////
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            EM_F[0] = 4*w0*y_p[0];
+                            EM_F[1] = 4*w0*y_p[0];
+                            EM_F[2] = 4*w0*y_p[0];
+                            EM_F[3] = 4*w0*y_p[0];
+                        }
+                        const index_t firstNode=m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k1 loop
+            } // colouring
+        } // face 4
+
+        if (domain->m_faceOffset[5] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F) {
+                EM_F[0] = 0;
+                EM_F[1] = 0;
+                EM_F[2] = 0;
+                EM_F[3] = 0;
+            }
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
+#pragma omp for
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
+                        ///////////////
+                        // process d //
+                        ///////////////
+                        if (add_EM_S) {
+                            const double* d_p=d.getSampleDataRO(e);
+                            EM_S[INDEX2(4,4,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(5,4,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(6,4,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(7,4,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(4,5,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(5,5,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(6,5,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(7,5,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(4,6,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(5,6,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(6,6,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(7,6,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(4,7,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(5,7,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(6,7,8)] = d_p[0]*w0;
+                            EM_S[INDEX2(7,7,8)] = d_p[0]*w0;
+                        }
+                        ///////////////
+                        // process y //
+                        ///////////////
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            EM_F[4] = 4*w0*y_p[0];
+                            EM_F[5] = 4*w0*y_p[0];
+                            EM_F[6] = 4*w0*y_p[0];
+                            EM_F[7] = 4*w0*y_p[0];
+                        }
+                        const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                               add_EM_S, add_EM_F, firstNode);
+                    } // k0 loop
+                } // k1 loop
+            } // colouring
+        } // face 5
+    } // end of parallel region
+}
+
+/****************************************************************************/
+// PDE SYSTEM
+/****************************************************************************/
+
+void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
+                                           const Data& A, const Data& B,
+                                           const Data& C, const Data& D,
+                                           const Data& X, const Data& Y) const
+{
+    dim_t numEq, numComp;
+    if (!mat)
+        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
+    else {
+        numEq=mat->getRowBlockSize();
+        numComp=mat->getColumnBlockSize();
+    }
+
+    const double SQRT3 = 1.73205080756887719318;
+    const double w10 = -m_dx[0]/288;
+    const double w12 = w10*(-SQRT3 - 2);
+    const double w6 = w10*(SQRT3 - 2);
+    const double w18 = w10*(-4*SQRT3 - 7);
+    const double w4 = w10*(-4*SQRT3 + 7);
+    const double w11 = m_dx[1]/288;
+    const double w15 = w11*(SQRT3 + 2);
+    const double w5 = w11*(-SQRT3 + 2);
+    const double w2 = w11*(4*SQRT3 - 7);
+    const double w17 = w11*(4*SQRT3 + 7);
+    const double w8 = m_dx[2]/288;
+    const double w16 = w8*(SQRT3 + 2);
+    const double w1 = w8*(-SQRT3 + 2);
+    const double w20 = w8*(4*SQRT3 - 7);
+    const double w21 = w8*(-4*SQRT3 - 7);
+    const double w54 = -m_dx[0]*m_dx[1]/72;
+    const double w68 = -m_dx[0]*m_dx[1]/48;
+    const double w38 = w68*(-SQRT3 - 3)/36;
+    const double w45 = w68*(SQRT3 - 3)/36;
+    const double w35 = w68*(5*SQRT3 - 9)/36;
+    const double w46 = w68*(-5*SQRT3 - 9)/36;
+    const double w43 = w68*(-19*SQRT3 - 33)/36;
+    const double w44 = w68*(19*SQRT3 - 33)/36;
+    const double w66 = w68*(SQRT3 + 2);
+    const double w70 = w68*(-SQRT3 + 2);
+    const double w56 = -m_dx[0]*m_dx[2]/72;
+    const double w67 = -m_dx[0]*m_dx[2]/48;
+    const double w37 = w67*(-SQRT3 - 3)/36;
+    const double w40 = w67*(SQRT3 - 3)/36;
+    const double w34 = w67*(5*SQRT3 - 9)/36;
+    const double w42 = w67*(-5*SQRT3 - 9)/36;
+    const double w47 = w67*(19*SQRT3 + 33)/36;
+    const double w48 = w67*(-19*SQRT3 + 33)/36;
+    const double w65 = w67*(SQRT3 + 2);
+    const double w71 = w67*(-SQRT3 + 2);
+    const double w55 = -m_dx[1]*m_dx[2]/72;
+    const double w69 = -m_dx[1]*m_dx[2]/48;
+    const double w36 = w69*(SQRT3 - 3)/36;
+    const double w39 = w69*(-SQRT3 - 3)/36;
+    const double w33 = w69*(5*SQRT3 - 9)/36;
+    const double w41 = w69*(-5*SQRT3 - 9)/36;
+    const double w49 = w69*(19*SQRT3 - 33)/36;
+    const double w50 = w69*(-19*SQRT3 - 33)/36;
+    const double w64 = w69*(SQRT3 + 2);
+    const double w72 = w69*(-SQRT3 + 2);
+    const double w58 = m_dx[0]*m_dx[1]*m_dx[2]/1728;
+    const double w60 = w58*(-SQRT3 + 2);
+    const double w61 = w58*(SQRT3 + 2);
+    const double w57 = w58*(-4*SQRT3 + 7);
+    const double w59 = w58*(4*SQRT3 + 7);
+    const double w62 = w58*(15*SQRT3 + 26);
+    const double w63 = w58*(-15*SQRT3 + 26);
+    const double w75 = w58*6*(SQRT3 + 3);
+    const double w76 = w58*6*(-SQRT3 + 3);
+    const double w74 = w58*6*(5*SQRT3 + 9);
+    const double w77 = w58*6*(-5*SQRT3 + 9);
+    const double w13 = -m_dx[0]*m_dx[1]/(288*m_dx[2]);
+    const double w19 = w13*(4*SQRT3 + 7);
+    const double w7 = w13*(-4*SQRT3 + 7);
+    const double w23 = w13*(+SQRT3 - 2);
+    const double w25 = w13*(-SQRT3 - 2);
+    const double w22 = -m_dx[0]*m_dx[2]/(288*m_dx[1]);
+    const double w3 = w22*(SQRT3 - 2);
+    const double w9 = w22*(-SQRT3 - 2);
+    const double w24 = w22*(4*SQRT3 + 7);
+    const double w26 = w22*(-4*SQRT3 + 7);
+    const double w27 = -m_dx[1]*m_dx[2]/(288*m_dx[0]);
+    const double w0 = w27*(SQRT3 - 2);
+    const double w14 = w27*(-SQRT3 - 2);
+    const double w28 = w27*(-4*SQRT3 + 7);
+    const double w29 = w27*(4*SQRT3 + 7);
+    const int NE0 = m_NE[0];
+    const int NE1 = m_NE[1];
+    const int NE2 = m_NE[2];
+    const bool add_EM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool add_EM_F = (!X.isEmpty() || !Y.isEmpty());
+    rhs.requireWrite();
+
+#pragma omp parallel
+    {
+        vector<double> EM_S(8*8*numEq*numComp, 0);
+        vector<double> EM_F(8*numEq, 0);
+
+        for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+#pragma omp for
+            for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                for (index_t k1=0; k1<NE1; ++k1) {
+                    for (index_t k0=0; k0<NE0; ++k0)  {
+                        const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                        if (add_EM_S)
+                            fill(EM_S.begin(), EM_S.end(), 0);
+                        if (add_EM_F)
+                            fill(EM_F.begin(), EM_F.end(), 0);
+
+                        ///////////////
+                        // process A //
+                        ///////////////
+                        if (!A.isEmpty()) {
+                            const double* A_p = A.getSampleDataRO(e);
+                            if (A.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double A_00_0 = A_p[INDEX5(k,0,m,0,0,numEq,3,numComp,3)];
+                                        const double A_01_0 = A_p[INDEX5(k,0,m,1,0,numEq,3,numComp,3)];
+                                        const double A_02_0 = A_p[INDEX5(k,0,m,2,0,numEq,3,numComp,3)];
+                                        const double A_10_0 = A_p[INDEX5(k,1,m,0,0,numEq,3,numComp,3)];
+                                        const double A_11_0 = A_p[INDEX5(k,1,m,1,0,numEq,3,numComp,3)];
+                                        const double A_12_0 = A_p[INDEX5(k,1,m,2,0,numEq,3,numComp,3)];
+                                        const double A_20_0 = A_p[INDEX5(k,2,m,0,0,numEq,3,numComp,3)];
+                                        const double A_21_0 = A_p[INDEX5(k,2,m,1,0,numEq,3,numComp,3)];
+                                        const double A_22_0 = A_p[INDEX5(k,2,m,2,0,numEq,3,numComp,3)];
+                                        const double A_00_1 = A_p[INDEX5(k,0,m,0,1,numEq,3,numComp,3)];
+                                        const double A_01_1 = A_p[INDEX5(k,0,m,1,1,numEq,3,numComp,3)];
+                                        const double A_02_1 = A_p[INDEX5(k,0,m,2,1,numEq,3,numComp,3)];
+                                        const double A_10_1 = A_p[INDEX5(k,1,m,0,1,numEq,3,numComp,3)];
+                                        const double A_11_1 = A_p[INDEX5(k,1,m,1,1,numEq,3,numComp,3)];
+                                        const double A_12_1 = A_p[INDEX5(k,1,m,2,1,numEq,3,numComp,3)];
+                                        const double A_20_1 = A_p[INDEX5(k,2,m,0,1,numEq,3,numComp,3)];
+                                        const double A_21_1 = A_p[INDEX5(k,2,m,1,1,numEq,3,numComp,3)];
+                                        const double A_22_1 = A_p[INDEX5(k,2,m,2,1,numEq,3,numComp,3)];
+                                        const double A_00_2 = A_p[INDEX5(k,0,m,0,2,numEq,3,numComp,3)];
+                                        const double A_01_2 = A_p[INDEX5(k,0,m,1,2,numEq,3,numComp,3)];
+                                        const double A_02_2 = A_p[INDEX5(k,0,m,2,2,numEq,3,numComp,3)];
+                                        const double A_10_2 = A_p[INDEX5(k,1,m,0,2,numEq,3,numComp,3)];
+                                        const double A_11_2 = A_p[INDEX5(k,1,m,1,2,numEq,3,numComp,3)];
+                                        const double A_12_2 = A_p[INDEX5(k,1,m,2,2,numEq,3,numComp,3)];
+                                        const double A_20_2 = A_p[INDEX5(k,2,m,0,2,numEq,3,numComp,3)];
+                                        const double A_21_2 = A_p[INDEX5(k,2,m,1,2,numEq,3,numComp,3)];
+                                        const double A_22_2 = A_p[INDEX5(k,2,m,2,2,numEq,3,numComp,3)];
+                                        const double A_00_3 = A_p[INDEX5(k,0,m,0,3,numEq,3,numComp,3)];
+                                        const double A_01_3 = A_p[INDEX5(k,0,m,1,3,numEq,3,numComp,3)];
+                                        const double A_02_3 = A_p[INDEX5(k,0,m,2,3,numEq,3,numComp,3)];
+                                        const double A_10_3 = A_p[INDEX5(k,1,m,0,3,numEq,3,numComp,3)];
+                                        const double A_11_3 = A_p[INDEX5(k,1,m,1,3,numEq,3,numComp,3)];
+                                        const double A_12_3 = A_p[INDEX5(k,1,m,2,3,numEq,3,numComp,3)];
+                                        const double A_20_3 = A_p[INDEX5(k,2,m,0,3,numEq,3,numComp,3)];
+                                        const double A_21_3 = A_p[INDEX5(k,2,m,1,3,numEq,3,numComp,3)];
+                                        const double A_22_3 = A_p[INDEX5(k,2,m,2,3,numEq,3,numComp,3)];
+                                        const double A_00_4 = A_p[INDEX5(k,0,m,0,4,numEq,3,numComp,3)];
+                                        const double A_01_4 = A_p[INDEX5(k,0,m,1,4,numEq,3,numComp,3)];
+                                        const double A_02_4 = A_p[INDEX5(k,0,m,2,4,numEq,3,numComp,3)];
+                                        const double A_10_4 = A_p[INDEX5(k,1,m,0,4,numEq,3,numComp,3)];
+                                        const double A_11_4 = A_p[INDEX5(k,1,m,1,4,numEq,3,numComp,3)];
+                                        const double A_12_4 = A_p[INDEX5(k,1,m,2,4,numEq,3,numComp,3)];
+                                        const double A_20_4 = A_p[INDEX5(k,2,m,0,4,numEq,3,numComp,3)];
+                                        const double A_21_4 = A_p[INDEX5(k,2,m,1,4,numEq,3,numComp,3)];
+                                        const double A_22_4 = A_p[INDEX5(k,2,m,2,4,numEq,3,numComp,3)];
+                                        const double A_00_5 = A_p[INDEX5(k,0,m,0,5,numEq,3,numComp,3)];
+                                        const double A_01_5 = A_p[INDEX5(k,0,m,1,5,numEq,3,numComp,3)];
+                                        const double A_02_5 = A_p[INDEX5(k,0,m,2,5,numEq,3,numComp,3)];
+                                        const double A_10_5 = A_p[INDEX5(k,1,m,0,5,numEq,3,numComp,3)];
+                                        const double A_11_5 = A_p[INDEX5(k,1,m,1,5,numEq,3,numComp,3)];
+                                        const double A_12_5 = A_p[INDEX5(k,1,m,2,5,numEq,3,numComp,3)];
+                                        const double A_20_5 = A_p[INDEX5(k,2,m,0,5,numEq,3,numComp,3)];
+                                        const double A_21_5 = A_p[INDEX5(k,2,m,1,5,numEq,3,numComp,3)];
+                                        const double A_22_5 = A_p[INDEX5(k,2,m,2,5,numEq,3,numComp,3)];
+                                        const double A_00_6 = A_p[INDEX5(k,0,m,0,6,numEq,3,numComp,3)];
+                                        const double A_01_6 = A_p[INDEX5(k,0,m,1,6,numEq,3,numComp,3)];
+                                        const double A_02_6 = A_p[INDEX5(k,0,m,2,6,numEq,3,numComp,3)];
+                                        const double A_10_6 = A_p[INDEX5(k,1,m,0,6,numEq,3,numComp,3)];
+                                        const double A_11_6 = A_p[INDEX5(k,1,m,1,6,numEq,3,numComp,3)];
+                                        const double A_12_6 = A_p[INDEX5(k,1,m,2,6,numEq,3,numComp,3)];
+                                        const double A_20_6 = A_p[INDEX5(k,2,m,0,6,numEq,3,numComp,3)];
+                                        const double A_21_6 = A_p[INDEX5(k,2,m,1,6,numEq,3,numComp,3)];
+                                        const double A_22_6 = A_p[INDEX5(k,2,m,2,6,numEq,3,numComp,3)];
+                                        const double A_00_7 = A_p[INDEX5(k,0,m,0,7,numEq,3,numComp,3)];
+                                        const double A_01_7 = A_p[INDEX5(k,0,m,1,7,numEq,3,numComp,3)];
+                                        const double A_02_7 = A_p[INDEX5(k,0,m,2,7,numEq,3,numComp,3)];
+                                        const double A_10_7 = A_p[INDEX5(k,1,m,0,7,numEq,3,numComp,3)];
+                                        const double A_11_7 = A_p[INDEX5(k,1,m,1,7,numEq,3,numComp,3)];
+                                        const double A_12_7 = A_p[INDEX5(k,1,m,2,7,numEq,3,numComp,3)];
+                                        const double A_20_7 = A_p[INDEX5(k,2,m,0,7,numEq,3,numComp,3)];
+                                        const double A_21_7 = A_p[INDEX5(k,2,m,1,7,numEq,3,numComp,3)];
+                                        const double A_22_7 = A_p[INDEX5(k,2,m,2,7,numEq,3,numComp,3)];
+                                        const double tmp0 = w18*(-A_12_7 + A_21_3);
+                                        const double tmp1 = w13*(A_22_1 + A_22_2 + A_22_5 + A_22_6);
+                                        const double tmp2 = w11*(-A_02_2 - A_02_5 + A_20_1 + A_20_6);
+                                        const double tmp3 = w14*(A_00_2 + A_00_3 + A_00_6 + A_00_7);
+                                        const double tmp4 = w7*(A_22_0 + A_22_4);
+                                        const double tmp5 = w10*(A_12_1 + A_12_6 - A_21_2 - A_21_5);
+                                        const double tmp6 = w3*(A_11_0 + A_11_2 + A_11_4 + A_11_6);
+                                        const double tmp7 = w1*(A_01_0 + A_01_4 + A_10_0 + A_10_4);
+                                        const double tmp8 = w4*(A_12_0 - A_21_4);
+                                        const double tmp9 = w15*(-A_02_3 - A_02_6 + A_20_2 + A_20_7);
+                                        const double tmp10 = w0*(A_00_0 + A_00_1 + A_00_4 + A_00_5);
+                                        const double tmp11 = w16*(A_01_3 + A_01_7 + A_10_3 + A_10_7);
+                                        const double tmp12 = w9*(A_11_1 + A_11_3 + A_11_5 + A_11_7);
+                                        const double tmp13 = w12*(-A_12_3 - A_12_5 + A_21_1 + A_21_7);
+                                        const double tmp14 = w5*(-A_02_1 - A_02_4 + A_20_0 + A_20_5);
+                                        const double tmp15 = w8*(A_01_1 + A_01_2 + A_01_5 + A_01_6 + A_10_1 + A_10_2 + A_10_5 + A_10_6);
+                                        const double tmp16 = w6*(-A_12_2 - A_12_4 + A_21_0 + A_21_6);
+                                        const double tmp17 = w19*(A_22_3 + A_22_7);
+                                        const double tmp18 = w17*(-A_02_7 + A_20_3);
+                                        const double tmp19 = w2*(A_02_0 - A_20_4);
+                                        const double tmp20 = w13*(-A_22_0 - A_22_1 - A_22_2 - A_22_3 - A_22_4 - A_22_5 - A_22_6 - A_22_7);
+                                        const double tmp21 = w11*(-A_02_1 - A_02_3 - A_02_4 - A_02_6 + A_20_0 + A_20_2 + A_20_5 + A_20_7);
+                                        const double tmp22 = w14*(-A_00_4 - A_00_5 - A_00_6 - A_00_7);
+                                        const double tmp23 = w20*(A_01_2 + A_10_1);
+                                        const double tmp24 = w10*(A_12_2 + A_12_3 + A_12_4 + A_12_5 - A_21_0 - A_21_1 - A_21_6 - A_21_7);
+                                        const double tmp25 = w3*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
+                                        const double tmp26 = w1*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
+                                        const double tmp27 = w15*(-A_02_5 - A_02_7 + A_20_4 + A_20_6);
+                                        const double tmp28 = w0*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
+                                        const double tmp29 = w16*(-A_01_4 - A_01_7 - A_10_4 - A_10_7);
+                                        const double tmp30 = w9*(-A_11_4 - A_11_5 - A_11_6 - A_11_7);
+                                        const double tmp31 = w21*(A_01_5 + A_10_6);
+                                        const double tmp32 = w12*(-A_12_6 - A_12_7 + A_21_4 + A_21_5);
+                                        const double tmp33 = w5*(-A_02_0 - A_02_2 + A_20_1 + A_20_3);
+                                        const double tmp34 = w8*(-A_01_1 - A_01_6 - A_10_2 - A_10_5);
+                                        const double tmp35 = w6*(-A_12_0 - A_12_1 + A_21_2 + A_21_3);
+                                        const double tmp36 = w20*(-A_01_6 + A_10_4);
+                                        const double tmp37 = w18*(A_12_3 - A_21_1);
+                                        const double tmp38 = w11*(-A_02_0 - A_02_2 - A_02_5 - A_02_7 - A_20_0 - A_20_2 - A_20_5 - A_20_7);
+                                        const double tmp39 = w14*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
+                                        const double tmp40 = w26*(A_11_4 + A_11_6);
+                                        const double tmp41 = w0*(A_00_4 + A_00_5 + A_00_6 + A_00_7);
+                                        const double tmp42 = w10*(-A_12_2 - A_12_5 + A_21_0 + A_21_7);
+                                        const double tmp43 = w22*(A_11_0 + A_11_2 + A_11_5 + A_11_7);
+                                        const double tmp44 = w1*(A_01_4 + A_01_7 - A_10_5 - A_10_6);
+                                        const double tmp45 = w25*(A_22_1 + A_22_3 + A_22_5 + A_22_7);
+                                        const double tmp46 = w4*(-A_12_4 + A_21_6);
+                                        const double tmp47 = w15*(-A_02_1 - A_02_3 - A_20_1 - A_20_3);
+                                        const double tmp48 = w21*(-A_01_1 + A_10_3);
+                                        const double tmp49 = w16*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
+                                        const double tmp50 = w5*(-A_02_4 - A_02_6 - A_20_4 - A_20_6);
+                                        const double tmp51 = w12*(A_12_1 + A_12_7 - A_21_3 - A_21_5);
+                                        const double tmp52 = w24*(A_11_1 + A_11_3);
+                                        const double tmp53 = w8*(A_01_2 + A_01_5 - A_10_0 - A_10_7);
+                                        const double tmp54 = w6*(A_12_0 + A_12_6 - A_21_2 - A_21_4);
+                                        const double tmp55 = w23*(A_22_0 + A_22_2 + A_22_4 + A_22_6);
+                                        const double tmp56 = w18*(A_12_4 - A_21_6);
+                                        const double tmp57 = w14*(A_00_4 + A_00_5 + A_00_6 + A_00_7);
+                                        const double tmp58 = w26*(A_11_1 + A_11_3);
+                                        const double tmp59 = w20*(-A_01_1 + A_10_3);
+                                        const double tmp60 = w1*(A_01_0 + A_01_3 - A_10_1 - A_10_2);
+                                        const double tmp61 = w25*(A_22_0 + A_22_2 + A_22_4 + A_22_6);
+                                        const double tmp62 = w4*(-A_12_3 + A_21_1);
+                                        const double tmp63 = w15*(-A_02_4 - A_02_6 - A_20_4 - A_20_6);
+                                        const double tmp64 = w0*(A_00_0 + A_00_1 + A_00_2 + A_00_3);
+                                        const double tmp65 = w16*(A_01_4 + A_01_7 - A_10_5 - A_10_6);
+                                        const double tmp66 = w24*(A_11_4 + A_11_6);
+                                        const double tmp67 = w21*(-A_01_6 + A_10_4);
+                                        const double tmp68 = w12*(A_12_0 + A_12_6 - A_21_2 - A_21_4);
+                                        const double tmp69 = w5*(-A_02_1 - A_02_3 - A_20_1 - A_20_3);
+                                        const double tmp70 = w6*(A_12_1 + A_12_7 - A_21_3 - A_21_5);
+                                        const double tmp71 = w23*(A_22_1 + A_22_3 + A_22_5 + A_22_7);
+                                        const double tmp72 = w20*(A_01_5 + A_10_6);
+                                        const double tmp73 = w14*(-A_00_0 - A_00_1 - A_00_2 - A_00_3);
+                                        const double tmp74 = w0*(-A_00_4 - A_00_5 - A_00_6 - A_00_7);
+                                        const double tmp75 = w3*(-A_11_4 - A_11_5 - A_11_6 - A_11_7);
+                                        const double tmp76 = w1*(-A_01_4 - A_01_7 - A_10_4 - A_10_7);
+                                        const double tmp77 = w15*(-A_02_0 - A_02_2 + A_20_1 + A_20_3);
+                                        const double tmp78 = w21*(A_01_2 + A_10_1);
+                                        const double tmp79 = w16*(-A_01_0 - A_01_3 - A_10_0 - A_10_3);
+                                        const double tmp80 = w9*(-A_11_0 - A_11_1 - A_11_2 - A_11_3);
+                                        const double tmp81 = w12*(-A_12_0 - A_12_1 + A_21_2 + A_21_3);
+                                        const double tmp82 = w5*(-A_02_5 - A_02_7 + A_20_4 + A_20_6);
+                                        const double tmp83 = w6*(-A_12_6 - A_12_7 + A_21_4 + A_21_5);
+                                        const double tmp84 = w6*(-A_12_2 - A_12_3 - A_21_2 - A_21_3);
+                                        const double tmp85 = w11*(A_02_1 + A_02_6 - A_20_0 - A_20_7);
+                                        const double tmp86 = w20*(A_01_3 - A_10_2);
+                                        const double tmp87 = w10*(A_12_0 + A_12_1 + A_12_6 + A_12_7 + A_21_0 + A_21_1 + A_21_6 + A_21_7);
+                                        const double tmp88 = w3*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
+                                        const double tmp89 = w23*(A_22_2 + A_22_3 + A_22_6 + A_22_7);
+                                        const double tmp90 = w1*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
+                                        const double tmp91 = w25*(A_22_0 + A_22_1 + A_22_4 + A_22_5);
+                                        const double tmp92 = w15*(A_02_0 + A_02_5 - A_20_1 - A_20_4);
+                                        const double tmp93 = w21*(A_01_4 - A_10_5);
+                                        const double tmp94 = w16*(-A_01_5 - A_01_6 + A_10_4 + A_10_7);
+                                        const double tmp95 = w28*(A_00_2 + A_00_3);
+                                        const double tmp96 = w12*(-A_12_4 - A_12_5 - A_21_4 - A_21_5);
+                                        const double tmp97 = w29*(A_00_4 + A_00_5);
+                                        const double tmp98 = w5*(A_02_2 + A_02_7 - A_20_3 - A_20_6);
+                                        const double tmp99 = w8*(-A_01_0 - A_01_7 + A_10_1 + A_10_6);
+                                        const double tmp100 = w9*(A_11_4 + A_11_5 + A_11_6 + A_11_7);
+                                        const double tmp101 = w27*(A_00_0 + A_00_1 + A_00_6 + A_00_7);
+                                        const double tmp102 = w17*(A_02_4 - A_20_5);
+                                        const double tmp103 = w2*(-A_02_3 + A_20_2);
+                                        const double tmp104 = w13*(A_22_0 + A_22_1 + A_22_2 + A_22_3 + A_22_4 + A_22_5 + A_22_6 + A_22_7);
+                                        const double tmp105 = w6*(-A_12_4 - A_12_5 - A_21_2 - A_21_3);
+                                        const double tmp106 = w22*(A_11_0 + A_11_1 + A_11_2 + A_11_3 + A_11_4 + A_11_5 + A_11_6 + A_11_7);
+                                        const double tmp107 = w1*(-A_01_2 - A_01_6 - A_10_1 - A_10_5);
+                                        const double tmp108 = w15*(-A_02_1 - A_02_3 - A_20_4 - A_20_6);
+                                        const double tmp109 = w16*(-A_01_1 - A_01_5 - A_10_2 - A_10_6);
+                                        const double tmp110 = w12*(-A_12_2 - A_12_3 - A_21_4 - A_21_5);
+                                        const double tmp111 = w5*(-A_02_4 - A_02_6 - A_20_1 - A_20_3);
+                                        const double tmp112 = w8*(-A_01_0 - A_01_3 - A_01_4 - A_01_7 - A_10_0 - A_10_3 - A_10_4 - A_10_7);
+                                        const double tmp113 = w27*(A_00_0 + A_00_1 + A_00_2 + A_00_3 + A_00_4 + A_00_5 + A_00_6 + A_00_7);
+                                        const double tmp114 = w11*(A_02_0 + A_02_2 + A_02_5 + A_02_7 - A_20_1 - A_20_3 - A_20_4 - A_20_6);
+                                        const double tmp115 = w21*(-A_01_4 - A_10_7);
+                                        const double tmp116 = w20*(-A_01_3 - A_10_0);
+                                        const double tmp117 = w15*(A_02_4 + A_02_6 - A_20_5 - A_20_7);
+                                        const double tmp118 = w16*(A_01_5 + A_01_6 + A_10_5 + A_10_6);
+                                        const double tmp119 = w5*(A_02_1 + A_02_3 - A_20_0 - A_20_2);
+                                        const double tmp120 = w8*(A_01_0 + A_01_7 + A_10_3 + A_10_4);
+                                        const double tmp121 = w1*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
+                                        const double tmp122 = w18*(A_12_2 - A_21_6);
+                                        const double tmp123 = w13*(A_22_0 + A_22_3 + A_22_4 + A_22_7);
+                                        const double tmp124 = w11*(-A_02_0 - A_02_7 + A_20_3 + A_20_4);
+                                        const double tmp125 = w7*(A_22_1 + A_22_5);
+                                        const double tmp126 = w10*(-A_12_3 - A_12_4 + A_21_0 + A_21_7);
+                                        const double tmp127 = w3*(A_11_1 + A_11_3 + A_11_5 + A_11_7);
+                                        const double tmp128 = w1*(-A_01_1 - A_01_5 - A_10_1 - A_10_5);
+                                        const double tmp129 = w4*(-A_12_5 + A_21_1);
+                                        const double tmp130 = w16*(-A_01_2 - A_01_6 - A_10_2 - A_10_6);
+                                        const double tmp131 = w9*(A_11_0 + A_11_2 + A_11_4 + A_11_6);
+                                        const double tmp132 = w19*(A_22_2 + A_22_6);
+                                        const double tmp133 = w17*(-A_02_2 + A_20_6);
+                                        const double tmp134 = w2*(A_02_5 - A_20_1);
+                                        const double tmp135 = w11*(A_02_1 + A_02_3 + A_02_4 + A_02_6 + A_20_1 + A_20_3 + A_20_4 + A_20_6);
+                                        const double tmp136 = w1*(A_01_3 + A_01_7 + A_10_0 + A_10_4);
+                                        const double tmp137 = w15*(A_02_0 + A_02_2 + A_20_5 + A_20_7);
+                                        const double tmp138 = w16*(A_01_0 + A_01_4 + A_10_3 + A_10_7);
+                                        const double tmp139 = w5*(A_02_5 + A_02_7 + A_20_0 + A_20_2);
+                                        const double tmp140 = w18*(A_12_5 - A_21_1);
+                                        const double tmp141 = w14*(A_00_0 + A_00_1 + A_00_4 + A_00_5);
+                                        const double tmp142 = w7*(A_22_2 + A_22_6);
+                                        const double tmp143 = w1*(-A_01_2 - A_01_6 - A_10_2 - A_10_6);
+                                        const double tmp144 = w4*(-A_12_2 + A_21_6);
+                                        const double tmp145 = w15*(-A_02_1 - A_02_4 + A_20_0 + A_20_5);
+                                        const double tmp146 = w0*(A_00_2 + A_00_3 + A_00_6 + A_00_7);
+                                        const double tmp147 = w16*(-A_01_1 - A_01_5 - A_10_1 - A_10_5);
+                                        const double tmp148 = w5*(-A_02_3 - A_02_6 + A_20_2 + A_20_7);
+                                        const double tmp149 = w19*(A_22_1 + A_22_5);
+                                        const double tmp150 = w17*(-A_02_5 + A_20_1);
+                                        const double tmp151 = w2*(A_02_2 - A_20_6);
+                                        const double tmp152 = w18*(A_12_3 - A_21_7);
+                                        const double tmp153 = w11*(A_02_1 + A_02_6 - A_20_2 - A_20_5);
+                                        const double tmp154 = w10*(-A_12_2 - A_12_5 + A_21_1 + A_21_6);
+                                        const double tmp155 = w4*(-A_12_4 + A_21_0);
+                                        const double tmp156 = w15*(A_02_2 + A_02_7 - A_20_3 - A_20_6);
+                                        const double tmp157 = w5*(A_02_0 + A_02_5 - A_20_1 - A_20_4);
+                                        const double tmp158 = w17*(A_02_3 - A_20_7);
+                                        const double tmp159 = w2*(-A_02_4 + A_20_0);
+                                        const double tmp160 = w6*(A_12_6 + A_12_7 + A_21_0 + A_21_1);
+                                        const double tmp161 = w10*(-A_12_2 - A_12_3 - A_12_4 - A_12_5 - A_21_2 - A_21_3 - A_21_4 - A_21_5);
+                                        const double tmp162 = w1*(A_01_0 + A_01_4 + A_10_3 + A_10_7);
+                                        const double tmp163 = w16*(A_01_3 + A_01_7 + A_10_0 + A_10_4);
+                                        const double tmp164 = w12*(A_12_0 + A_12_1 + A_21_6 + A_21_7);
+                                        const double tmp165 = w20*(A_01_6 + A_10_5);
+                                        const double tmp166 = w10*(-A_12_0 - A_12_1 - A_12_6 - A_12_7 + A_21_2 + A_21_3 + A_21_4 + A_21_5);
+                                        const double tmp167 = w15*(A_02_1 + A_02_3 - A_20_0 - A_20_2);
+                                        const double tmp168 = w21*(A_01_1 + A_10_2);
+                                        const double tmp169 = w12*(A_12_2 + A_12_3 - A_21_0 - A_21_1);
+                                        const double tmp170 = w5*(A_02_4 + A_02_6 - A_20_5 - A_20_7);
+                                        const double tmp171 = w8*(-A_01_2 - A_01_5 - A_10_1 - A_10_6);
+                                        const double tmp172 = w6*(A_12_4 + A_12_5 - A_21_6 - A_21_7);
+                                        const double tmp173 = w2*(A_02_1 + A_20_4);
+                                        const double tmp174 = w11*(-A_02_3 - A_02_4 - A_20_1 - A_20_6);
+                                        const double tmp175 = w14*(-A_00_2 - A_00_3 - A_00_6 - A_00_7);
+                                        const double tmp176 = w22*(-A_11_0 - A_11_1 - A_11_2 - A_11_3 - A_11_4 - A_11_5 - A_11_6 - A_11_7);
+                                        const double tmp177 = w1*(A_01_1 + A_01_5 - A_10_0 - A_10_4);
+                                        const double tmp178 = w25*(-A_22_2 - A_22_3 - A_22_6 - A_22_7);
+                                        const double tmp179 = w15*(-A_02_2 - A_02_7 - A_20_2 - A_20_7);
+                                        const double tmp180 = w0*(-A_00_0 - A_00_1 - A_00_4 - A_00_5);
+                                        const double tmp181 = w16*(A_01_2 + A_01_6 - A_10_3 - A_10_7);
+                                        const double tmp182 = w12*(-A_12_6 - A_12_7 + A_21_2 + A_21_3);
+                                        const double tmp183 = w5*(-A_02_0 - A_02_5 - A_20_0 - A_20_5);
+                                        const double tmp184 = w8*(A_01_0 + A_01_3 + A_01_4 + A_01_7 - A_10_1 - A_10_2 - A_10_5 - A_10_6);
+                                        const double tmp185 = w6*(-A_12_0 - A_12_1 + A_21_4 + A_21_5);
+                                        const double tmp186 = w17*(-A_02_6 - A_20_3);
+                                        const double tmp187 = w23*(-A_22_0 - A_22_1 - A_22_4 - A_22_5);
+                                        const double tmp188 = w18*(A_12_4 - A_21_0);
+                                        const double tmp189 = w7*(A_22_3 + A_22_7);
+                                        const double tmp190 = w1*(A_01_3 + A_01_7 + A_10_3 + A_10_7);
+                                        const double tmp191 = w4*(-A_12_3 + A_21_7);
+                                        const double tmp192 = w16*(A_01_0 + A_01_4 + A_10_0 + A_10_4);
+                                        const double tmp193 = w19*(A_22_0 + A_22_4);
+                                        const double tmp194 = w17*(A_02_4 - A_20_0);
+                                        const double tmp195 = w2*(-A_02_3 + A_20_7);
+                                        const double tmp196 = w20*(-A_01_7 - A_10_4);
+                                        const double tmp197 = w21*(-A_01_0 - A_10_3);
+                                        const double tmp198 = w16*(A_01_1 + A_01_2 + A_10_1 + A_10_2);
+                                        const double tmp199 = w8*(A_01_3 + A_01_4 + A_10_0 + A_10_7);
+                                        const double tmp200 = w1*(A_01_5 + A_01_6 + A_10_5 + A_10_6);
+                                        const double tmp201 = w27*(A_00_2 + A_00_3 + A_00_4 + A_00_5);
+                                        const double tmp202 = w11*(-A_02_2 - A_02_5 + A_20_3 + A_20_4);
+                                        const double tmp203 = w20*(A_01_0 - A_10_1);
+                                        const double tmp204 = w23*(A_22_0 + A_22_1 + A_22_4 + A_22_5);
+                                        const double tmp205 = w25*(A_22_2 + A_22_3 + A_22_6 + A_22_7);
+                                        const double tmp206 = w21*(A_01_7 - A_10_6);
+                                        const double tmp207 = w12*(A_12_6 + A_12_7 + A_21_6 + A_21_7);
+                                        const double tmp208 = w28*(A_00_0 + A_00_1);
+                                        const double tmp209 = w29*(A_00_6 + A_00_7);
+                                        const double tmp210 = w8*(-A_01_3 - A_01_4 + A_10_2 + A_10_5);
+                                        const double tmp211 = w6*(A_12_0 + A_12_1 + A_21_0 + A_21_1);
+                                        const double tmp212 = w17*(-A_02_7 + A_20_6);
+                                        const double tmp213 = w2*(A_02_0 - A_20_1);
+                                        const double tmp214 = w13*(-A_22_1 - A_22_2 - A_22_5 - A_22_6);
+                                        const double tmp215 = w22*(-A_11_0 - A_11_2 - A_11_5 - A_11_7);
+                                        const double tmp216 = w8*(A_01_0 + A_01_7 + A_10_0 + A_10_7);
+                                        const double tmp217 = w27*(-A_00_0 - A_00_1 - A_00_6 - A_00_7);
+                                        const double tmp218 = w17*(-A_02_3 - A_20_3);
+                                        const double tmp219 = w2*(A_02_4 + A_20_4);
+                                        const double tmp220 = w11*(-A_02_1 - A_02_6 - A_20_1 - A_20_6);
+                                        const double tmp221 = w26*(-A_11_4 - A_11_6);
+                                        const double tmp222 = w10*(A_12_2 + A_12_5 + A_21_2 + A_21_5);
+                                        const double tmp223 = w20*(-A_01_4 - A_10_4);
+                                        const double tmp224 = w21*(-A_01_3 - A_10_3);
+                                        const double tmp225 = w6*(-A_12_0 - A_12_6 - A_21_0 - A_21_6);
+                                        const double tmp226 = w7*(-A_22_0 - A_22_4);
+                                        const double tmp227 = w24*(-A_11_1 - A_11_3);
+                                        const double tmp228 = w19*(-A_22_3 - A_22_7);
+                                        const double tmp229 = w18*(-A_12_3 - A_21_3);
+                                        const double tmp230 = w4*(A_12_4 + A_21_4);
+                                        const double tmp231 = w28*(-A_00_4 - A_00_5);
+                                        const double tmp232 = w12*(-A_12_1 - A_12_7 - A_21_1 - A_21_7);
+                                        const double tmp233 = w29*(-A_00_2 - A_00_3);
+                                        const double tmp234 = w20*(-A_01_5 + A_10_7);
+                                        const double tmp235 = w18*(-A_12_0 + A_21_2);
+                                        const double tmp236 = w26*(A_11_5 + A_11_7);
+                                        const double tmp237 = w10*(A_12_1 + A_12_6 - A_21_3 - A_21_4);
+                                        const double tmp238 = w22*(A_11_1 + A_11_3 + A_11_4 + A_11_6);
+                                        const double tmp239 = w4*(A_12_7 - A_21_5);
+                                        const double tmp240 = w15*(A_02_0 + A_02_2 + A_20_0 + A_20_2);
+                                        const double tmp241 = w21*(-A_01_2 + A_10_0);
+                                        const double tmp242 = w5*(A_02_5 + A_02_7 + A_20_5 + A_20_7);
+                                        const double tmp243 = w12*(-A_12_2 - A_12_4 + A_21_0 + A_21_6);
+                                        const double tmp244 = w24*(A_11_0 + A_11_2);
+                                        const double tmp245 = w8*(A_01_1 + A_01_6 - A_10_3 - A_10_4);
+                                        const double tmp246 = w6*(-A_12_3 - A_12_5 + A_21_1 + A_21_7);
+                                        const double tmp247 = w11*(A_02_3 + A_02_4 - A_20_2 - A_20_5);
+                                        const double tmp248 = w20*(-A_01_1 + A_10_0);
+                                        const double tmp249 = w21*(-A_01_6 + A_10_7);
+                                        const double tmp250 = w8*(A_01_2 + A_01_5 - A_10_3 - A_10_4);
+                                        const double tmp251 = w17*(A_02_6 - A_20_7);
+                                        const double tmp252 = w2*(-A_02_1 + A_20_0);
+                                        const double tmp253 = w17*(-A_02_4 - A_20_4);
+                                        const double tmp254 = w2*(A_02_3 + A_20_3);
+                                        const double tmp255 = w26*(-A_11_1 - A_11_3);
+                                        const double tmp256 = w20*(-A_01_3 - A_10_3);
+                                        const double tmp257 = w21*(-A_01_4 - A_10_4);
+                                        const double tmp258 = w6*(-A_12_1 - A_12_7 - A_21_1 - A_21_7);
+                                        const double tmp259 = w7*(-A_22_3 - A_22_7);
+                                        const double tmp260 = w15*(-A_02_0 - A_02_5 - A_20_0 - A_20_5);
+                                        const double tmp261 = w24*(-A_11_4 - A_11_6);
+                                        const double tmp262 = w19*(-A_22_0 - A_22_4);
+                                        const double tmp263 = w18*(-A_12_4 - A_21_4);
+                                        const double tmp264 = w4*(A_12_3 + A_21_3);
+                                        const double tmp265 = w28*(-A_00_2 - A_00_3);
+                                        const double tmp266 = w12*(-A_12_0 - A_12_6 - A_21_0 - A_21_6);
+                                        const double tmp267 = w5*(-A_02_2 - A_02_7 - A_20_2 - A_20_7);
+                                        const double tmp268 = w29*(-A_00_4 - A_00_5);
+                                        const double tmp269 = w11*(A_02_2 + A_02_5 + A_20_0 + A_20_7);
+                                        const double tmp270 = w1*(-A_01_0 - A_01_4 + A_10_1 + A_10_5);
+                                        const double tmp271 = w15*(A_02_3 + A_02_6 + A_20_3 + A_20_6);
+                                        const double tmp272 = w16*(-A_01_3 - A_01_7 + A_10_2 + A_10_6);
+                                        const double tmp273 = w5*(A_02_1 + A_02_4 + A_20_1 + A_20_4);
+                                        const double tmp274 = w8*(-A_01_1 - A_01_2 - A_01_5 - A_01_6 + A_10_0 + A_10_3 + A_10_4 + A_10_7);
+                                        const double tmp275 = w17*(A_02_7 + A_20_2);
+                                        const double tmp276 = w2*(-A_02_0 - A_20_5);
+                                        const double tmp277 = w18*(-A_12_1 + A_21_5);
+                                        const double tmp278 = w11*(A_02_3 + A_02_4 - A_20_0 - A_20_7);
+                                        const double tmp279 = w10*(A_12_0 + A_12_7 - A_21_3 - A_21_4);
+                                        const double tmp280 = w4*(A_12_6 - A_21_2);
+                                        const double tmp281 = w17*(A_02_1 - A_20_5);
+                                        const double tmp282 = w2*(-A_02_6 + A_20_2);
+                                        const double tmp283 = w11*(A_02_0 + A_02_7 + A_20_2 + A_20_5);
+                                        const double tmp284 = w12*(A_12_2 + A_12_3 - A_21_6 - A_21_7);
+                                        const double tmp285 = w6*(A_12_4 + A_12_5 - A_21_0 - A_21_1);
+                                        const double tmp286 = w17*(A_02_2 + A_20_7);
+                                        const double tmp287 = w2*(-A_02_5 - A_20_0);
+                                        const double tmp288 = w13*(-A_22_0 - A_22_3 - A_22_4 - A_22_7);
+                                        const double tmp289 = w22*(-A_11_1 - A_11_3 - A_11_4 - A_11_6);
+                                        const double tmp290 = w8*(-A_01_1 - A_01_6 - A_10_1 - A_10_6);
+                                        const double tmp291 = w17*(A_02_2 + A_20_2);
+                                        const double tmp292 = w2*(-A_02_5 - A_20_5);
+                                        const double tmp293 = w11*(A_02_0 + A_02_7 + A_20_0 + A_20_7);
+                                        const double tmp294 = w26*(-A_11_5 - A_11_7);
+                                        const double tmp295 = w10*(A_12_3 + A_12_4 + A_21_3 + A_21_4);
+                                        const double tmp296 = w20*(A_01_5 + A_10_5);
+                                        const double tmp297 = w21*(A_01_2 + A_10_2);
+                                        const double tmp298 = w7*(-A_22_1 - A_22_5);
+                                        const double tmp299 = w24*(-A_11_0 - A_11_2);
+                                        const double tmp300 = w19*(-A_22_2 - A_22_6);
+                                        const double tmp301 = w18*(-A_12_2 - A_21_2);
+                                        const double tmp302 = w4*(A_12_5 + A_21_5);
+                                        const double tmp303 = w8*(A_01_3 + A_01_4 + A_10_3 + A_10_4);
+                                        const double tmp304 = w27*(-A_00_2 - A_00_3 - A_00_4 - A_00_5);
+                                        const double tmp305 = w17*(A_02_7 + A_20_7);
+                                        const double tmp306 = w2*(-A_02_0 - A_20_0);
+                                        const double tmp307 = w11*(A_02_2 + A_02_5 + A_20_2 + A_20_5);
+                                        const double tmp308 = w26*(-A_11_0 - A_11_2);
+                                        const double tmp309 = w10*(-A_12_1 - A_12_6 - A_21_1 - A_21_6);
+                                        const double tmp310 = w20*(-A_01_0 - A_10_0);
+                                        const double tmp311 = w21*(-A_01_7 - A_10_7);
+                                        const double tmp312 = w6*(A_12_2 + A_12_4 + A_21_2 + A_21_4);
+                                        const double tmp313 = w24*(-A_11_5 - A_11_7);
+                                        const double tmp314 = w18*(A_12_7 + A_21_7);
+                                        const double tmp315 = w4*(-A_12_0 - A_21_0);
+                                        const double tmp316 = w28*(-A_00_0 - A_00_1);
+                                        const double tmp317 = w12*(A_12_3 + A_12_5 + A_21_3 + A_21_5);
+                                        const double tmp318 = w29*(-A_00_6 - A_00_7);
+                                        const double tmp319 = w18*(-A_12_7 + A_21_5);
+                                        const double tmp320 = w26*(A_11_0 + A_11_2);
+                                        const double tmp321 = w21*(-A_01_5 + A_10_7);
+                                        const double tmp322 = w20*(-A_01_2 + A_10_0);
+                                        const double tmp323 = w4*(A_12_0 - A_21_2);
+                                        const double tmp324 = w15*(A_02_5 + A_02_7 + A_20_5 + A_20_7);
+                                        const double tmp325 = w24*(A_11_5 + A_11_7);
+                                        const double tmp326 = w5*(A_02_0 + A_02_2 + A_20_0 + A_20_2);
+                                        const double tmp327 = w18*(A_12_7 + A_21_1);
+                                        const double tmp328 = w10*(-A_12_1 - A_12_6 - A_21_0 - A_21_7);
+                                        const double tmp329 = w3*(-A_11_0 - A_11_2 - A_11_4 - A_11_6);
+                                        const double tmp330 = w1*(A_01_2 + A_01_6 - A_10_0 - A_10_4);
+                                        const double tmp331 = w4*(-A_12_0 - A_21_6);
+                                        const double tmp332 = w25*(-A_22_1 - A_22_3 - A_22_5 - A_22_7);
+                                        const double tmp333 = w15*(-A_02_5 - A_02_7 + A_20_1 + A_20_3);
+                                        const double tmp334 = w16*(A_01_1 + A_01_5 - A_10_3 - A_10_7);
+                                        const double tmp335 = w9*(-A_11_1 - A_11_3 - A_11_5 - A_11_7);
+                                        const double tmp336 = w5*(-A_02_0 - A_02_2 + A_20_4 + A_20_6);
+                                        const double tmp337 = w27*(-A_00_0 - A_00_1 - A_00_2 - A_00_3 - A_00_4 - A_00_5 - A_00_6 - A_00_7);
+                                        const double tmp338 = w23*(-A_22_0 - A_22_2 - A_22_4 - A_22_6);
+                                        const double tmp339 = w14*(-A_00_0 - A_00_1 - A_00_4 - A_00_5);
+                                        const double tmp340 = w23*(-A_22_2 - A_22_3 - A_22_6 - A_22_7);
+                                        const double tmp341 = w1*(A_01_2 + A_01_6 - A_10_3 - A_10_7);
+                                        const double tmp342 = w25*(-A_22_0 - A_22_1 - A_22_4 - A_22_5);
+                                        const double tmp343 = w15*(A_02_1 + A_02_4 + A_20_1 + A_20_4);
+                                        const double tmp344 = w0*(-A_00_2 - A_00_3 - A_00_6 - A_00_7);
+                                        const double tmp345 = w16*(A_01_1 + A_01_5 - A_10_0 - A_10_4);
+                                        const double tmp346 = w12*(A_12_4 + A_12_5 - A_21_0 - A_21_1);
+                                        const double tmp347 = w5*(A_02_3 + A_02_6 + A_20_3 + A_20_6);
+                                        const double tmp348 = w6*(A_12_2 + A_12_3 - A_21_6 - A_21_7);
+                                        const double tmp349 = w17*(A_02_5 + A_20_0);
+                                        const double tmp350 = w2*(-A_02_2 - A_20_7);
+                                        const double tmp351 = w8*(-A_01_2 - A_01_5 - A_10_2 - A_10_5);
+                                        const double tmp352 = w17*(-A_02_1 - A_20_1);
+                                        const double tmp353 = w2*(A_02_6 + A_20_6);
+                                        const double tmp354 = w11*(-A_02_3 - A_02_4 - A_20_3 - A_20_4);
+                                        const double tmp355 = w10*(-A_12_0 - A_12_7 - A_21_0 - A_21_7);
+                                        const double tmp356 = w20*(A_01_6 + A_10_6);
+                                        const double tmp357 = w21*(A_01_1 + A_10_1);
+                                        const double tmp358 = w7*(-A_22_2 - A_22_6);
+                                        const double tmp359 = w19*(-A_22_1 - A_22_5);
+                                        const double tmp360 = w18*(A_12_1 + A_21_1);
+                                        const double tmp361 = w4*(-A_12_6 - A_21_6);
+                                        const double tmp362 = w28*(-A_00_6 - A_00_7);
+                                        const double tmp363 = w29*(-A_00_0 - A_00_1);
+                                        const double tmp364 = w2*(A_02_4 + A_20_1);
+                                        const double tmp365 = w11*(-A_02_1 - A_02_6 - A_20_3 - A_20_4);
+                                        const double tmp366 = w17*(-A_02_3 - A_20_6);
+                                        const double tmp367 = w2*(A_02_5 - A_20_4);
+                                        const double tmp368 = w6*(-A_12_4 - A_12_5 - A_21_4 - A_21_5);
+                                        const double tmp369 = w11*(-A_02_0 - A_02_7 + A_20_1 + A_20_6);
+                                        const double tmp370 = w20*(-A_01_5 + A_10_4);
+                                        const double tmp371 = w3*(A_11_4 + A_11_5 + A_11_6 + A_11_7);
+                                        const double tmp372 = w12*(-A_12_2 - A_12_3 - A_21_2 - A_21_3);
+                                        const double tmp373 = w21*(-A_01_2 + A_10_3);
+                                        const double tmp374 = w9*(A_11_0 + A_11_1 + A_11_2 + A_11_3);
+                                        const double tmp375 = w29*(A_00_2 + A_00_3);
+                                        const double tmp376 = w8*(A_01_1 + A_01_6 - A_10_0 - A_10_7);
+                                        const double tmp377 = w28*(A_00_4 + A_00_5);
+                                        const double tmp378 = w17*(-A_02_2 + A_20_3);
+                                        const double tmp379 = w17*(A_02_0 + A_20_0);
+                                        const double tmp380 = w2*(-A_02_7 - A_20_7);
+                                        const double tmp381 = w20*(-A_01_7 - A_10_7);
+                                        const double tmp382 = w21*(-A_01_0 - A_10_0);
+                                        const double tmp383 = w6*(A_12_3 + A_12_5 + A_21_3 + A_21_5);
+                                        const double tmp384 = w18*(A_12_0 + A_21_0);
+                                        const double tmp385 = w4*(-A_12_7 - A_21_7);
+                                        const double tmp386 = w12*(A_12_2 + A_12_4 + A_21_2 + A_21_4);
+                                        const double tmp387 = w17*(-A_02_6 - A_20_6);
+                                        const double tmp388 = w2*(A_02_1 + A_20_1);
+                                        const double tmp389 = w20*(A_01_1 + A_10_1);
+                                        const double tmp390 = w21*(A_01_6 + A_10_6);
+                                        const double tmp391 = w18*(A_12_6 + A_21_6);
+                                        const double tmp392 = w4*(-A_12_1 - A_21_1);
+                                        const double tmp393 = w2*(A_02_3 + A_20_6);
+                                        const double tmp394 = w1*(-A_01_3 - A_01_7 + A_10_2 + A_10_6);
+                                        const double tmp395 = w16*(-A_01_0 - A_01_4 + A_10_1 + A_10_5);
+                                        const double tmp396 = w17*(-A_02_4 - A_20_1);
+                                        const double tmp397 = w18*(-A_12_5 - A_21_3);
+                                        const double tmp398 = w10*(A_12_3 + A_12_4 + A_21_2 + A_21_5);
+                                        const double tmp399 = w1*(-A_01_0 - A_01_4 + A_10_2 + A_10_6);
+                                        const double tmp400 = w4*(A_12_2 + A_21_4);
+                                        const double tmp401 = w16*(-A_01_3 - A_01_7 + A_10_1 + A_10_5);
+                                        const double tmp402 = w20*(-A_01_2 + A_10_3);
+                                        const double tmp403 = w21*(-A_01_5 + A_10_4);
+                                        const double tmp404 = w17*(-A_02_5 + A_20_4);
+                                        const double tmp405 = w2*(A_02_2 - A_20_3);
+                                        const double tmp406 = w18*(-A_12_0 + A_21_4);
+                                        const double tmp407 = w4*(A_12_7 - A_21_3);
+                                        const double tmp408 = w17*(-A_02_0 + A_20_4);
+                                        const double tmp409 = w2*(A_02_7 - A_20_3);
+                                        const double tmp410 = w17*(A_02_5 + A_20_5);
+                                        const double tmp411 = w2*(-A_02_2 - A_20_2);
+                                        const double tmp412 = w20*(A_01_2 + A_10_2);
+                                        const double tmp413 = w21*(A_01_5 + A_10_5);
+                                        const double tmp414 = w18*(-A_12_5 - A_21_5);
+                                        const double tmp415 = w4*(A_12_2 + A_21_2);
+                                        const double tmp416 = w12*(-A_12_0 - A_12_1 + A_21_4 + A_21_5);
+                                        const double tmp417 = w6*(-A_12_6 - A_12_7 + A_21_2 + A_21_3);
+                                        const double tmp418 = w17*(A_02_0 + A_20_5);
+                                        const double tmp419 = w2*(-A_02_7 - A_20_2);
+                                        const double tmp420 = w18*(-A_12_4 - A_21_2);
+                                        const double tmp421 = w10*(A_12_2 + A_12_5 + A_21_3 + A_21_4);
+                                        const double tmp422 = w3*(-A_11_1 - A_11_3 - A_11_5 - A_11_7);
+                                        const double tmp423 = w1*(A_01_1 + A_01_5 - A_10_3 - A_10_7);
+                                        const double tmp424 = w25*(-A_22_0 - A_22_2 - A_22_4 - A_22_6);
+                                        const double tmp425 = w4*(A_12_3 + A_21_5);
+                                        const double tmp426 = w15*(A_02_4 + A_02_6 - A_20_0 - A_20_2);
+                                        const double tmp427 = w16*(A_01_2 + A_01_6 - A_10_0 - A_10_4);
+                                        const double tmp428 = w9*(-A_11_0 - A_11_2 - A_11_4 - A_11_6);
+                                        const double tmp429 = w5*(A_02_1 + A_02_3 - A_20_5 - A_20_7);
+                                        const double tmp430 = w23*(-A_22_1 - A_22_3 - A_22_5 - A_22_7);
+                                        const double tmp431 = w18*(A_12_5 - A_21_7);
+                                        const double tmp432 = w10*(-A_12_3 - A_12_4 + A_21_1 + A_21_6);
+                                        const double tmp433 = w21*(A_01_7 - A_10_5);
+                                        const double tmp434 = w20*(A_01_0 - A_10_2);
+                                        const double tmp435 = w4*(-A_12_2 + A_21_0);
+                                        const double tmp436 = w8*(-A_01_3 - A_01_4 + A_10_1 + A_10_6);
+                                        const double tmp437 = w2*(-A_02_4 + A_20_5);
+                                        const double tmp438 = w20*(A_01_4 - A_10_5);
+                                        const double tmp439 = w21*(A_01_3 - A_10_2);
+                                        const double tmp440 = w16*(-A_01_1 - A_01_2 + A_10_0 + A_10_3);
+                                        const double tmp441 = w1*(-A_01_5 - A_01_6 + A_10_4 + A_10_7);
+                                        const double tmp442 = w17*(A_02_3 - A_20_2);
+                                        const double tmp443 = w20*(-A_01_4 - A_10_7);
+                                        const double tmp444 = w21*(-A_01_3 - A_10_0);
+                                        const double tmp445 = w18*(A_12_6 + A_21_0);
+                                        const double tmp446 = w10*(-A_12_0 - A_12_7 - A_21_1 - A_21_6);
+                                        const double tmp447 = w1*(-A_01_3 - A_01_7 + A_10_1 + A_10_5);
+                                        const double tmp448 = w4*(-A_12_1 - A_21_7);
+                                        const double tmp449 = w16*(-A_01_0 - A_01_4 + A_10_2 + A_10_6);
+                                        const double tmp450 = w2*(A_02_7 - A_20_6);
+                                        const double tmp451 = w6*(A_12_6 + A_12_7 + A_21_6 + A_21_7);
+                                        const double tmp452 = w20*(A_01_7 - A_10_6);
+                                        const double tmp453 = w21*(A_01_0 - A_10_1);
+                                        const double tmp454 = w12*(A_12_0 + A_12_1 + A_21_0 + A_21_1);
+                                        const double tmp455 = w29*(A_00_0 + A_00_1);
+                                        const double tmp456 = w28*(A_00_6 + A_00_7);
+                                        const double tmp457 = w17*(-A_02_0 + A_20_1);
+                                        const double tmp458 = w21*(-A_01_7 - A_10_4);
+                                        const double tmp459 = w20*(-A_01_0 - A_10_3);
+                                        const double tmp460 = w12*(A_12_4 + A_12_5 - A_21_6 - A_21_7);
+                                        const double tmp461 = w6*(A_12_2 + A_12_3 - A_21_0 - A_21_1);
+                                        const double tmp462 = w18*(A_12_1 + A_21_7);
+                                        const double tmp463 = w4*(-A_12_6 - A_21_0);
+                                        const double tmp464 = w15*(A_02_1 + A_02_3 - A_20_5 - A_20_7);
+                                        const double tmp465 = w5*(A_02_4 + A_02_6 - A_20_0 - A_20_2);
+                                        const double tmp466 = w2*(-A_02_6 + A_20_7);
+                                        const double tmp467 = w20*(-A_01_6 + A_10_7);
+                                        const double tmp468 = w21*(-A_01_1 + A_10_0);
+                                        const double tmp469 = w17*(A_02_1 - A_20_0);
+                                        const double tmp470 = w6*(-A_12_2 - A_12_3 - A_21_4 - A_21_5);
+                                        const double tmp471 = w1*(-A_01_1 - A_01_5 - A_10_2 - A_10_6);
+                                        const double tmp472 = w15*(-A_02_4 - A_02_6 - A_20_1 - A_20_3);
+                                        const double tmp473 = w16*(-A_01_2 - A_01_6 - A_10_1 - A_10_5);
+                                        const double tmp474 = w12*(-A_12_4 - A_12_5 - A_21_2 - A_21_3);
+                                        const double tmp475 = w5*(-A_02_1 - A_02_3 - A_20_4 - A_20_6);
+                                        const double tmp476 = w18*(-A_12_6 + A_21_4);
+                                        const double tmp477 = w20*(A_01_3 - A_10_1);
+                                        const double tmp478 = w10*(A_12_0 + A_12_7 - A_21_2 - A_21_5);
+                                        const double tmp479 = w4*(A_12_1 - A_21_3);
+                                        const double tmp480 = w21*(A_01_4 - A_10_6);
+                                        const double tmp481 = w8*(-A_01_0 - A_01_7 + A_10_2 + A_10_5);
+                                        const double tmp482 = w6*(A_12_0 + A_12_1 + A_21_6 + A_21_7);
+                                        const double tmp483 = w12*(A_12_6 + A_12_7 + A_21_0 + A_21_1);
+                                        const double tmp484 = w15*(A_02_5 + A_02_7 + A_20_0 + A_20_2);
+                                        const double tmp485 = w5*(A_02_0 + A_02_2 + A_20_5 + A_20_7);
+                                        const double tmp486 = w18*(-A_12_1 + A_21_3);
+                                        const double tmp487 = w20*(A_01_4 - A_10_6);
+                                        const double tmp488 = w4*(A_12_6 - A_21_4);
+                                        const double tmp489 = w21*(A_01_3 - A_10_1);
+                                        const double tmp490 = w20*(A_01_7 - A_10_5);
+                                        const double tmp491 = w18*(A_12_2 - A_21_0);
+                                        const double tmp492 = w4*(-A_12_5 + A_21_7);
+                                        const double tmp493 = w21*(A_01_0 - A_10_2);
+                                        const double tmp494 = w20*(A_01_1 + A_10_2);
+                                        const double tmp495 = w21*(A_01_6 + A_10_5);
+                                        const double tmp496 = w18*(-A_12_2 - A_21_4);
+                                        const double tmp497 = w4*(A_12_5 + A_21_3);
+                                        const double tmp498 = w15*(-A_02_0 - A_02_2 + A_20_4 + A_20_6);
+                                        const double tmp499 = w5*(-A_02_5 - A_02_7 + A_20_1 + A_20_3);
+                                        const double tmp500 = w18*(-A_12_6 + A_21_2);
+                                        const double tmp501 = w4*(A_12_1 - A_21_5);
+                                        const double tmp502 = w17*(A_02_6 - A_20_2);
+                                        const double tmp503 = w2*(-A_02_1 + A_20_5);
+                                        const double tmp504 = w18*(-A_12_3 - A_21_5);
+                                        const double tmp505 = w4*(A_12_4 + A_21_2);
+                                        const double tmp506 = w2*(A_02_6 + A_20_3);
+                                        const double tmp507 = w17*(-A_02_1 - A_20_4);
+                                        const double tmp508 = w18*(A_12_0 + A_21_6);
+                                        const double tmp509 = w4*(-A_12_7 - A_21_1);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=tmp198 + tmp200 + tmp214 + tmp259 + tmp262 + tmp289 + tmp294 + tmp299 + tmp303 + tmp304 + tmp307 + tmp309 + tmp343 + tmp347 + tmp362 + tmp363 + tmp379 + tmp380 + tmp381 + tmp382 + tmp383 + tmp384 + tmp385 + tmp386;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp161 + tmp201 + tmp247 + tmp250 + tmp371 + tmp374 + tmp44 + tmp451 + tmp454 + tmp455 + tmp456 + tmp466 + tmp467 + tmp468 + tmp469 + tmp49 + tmp89 + tmp91 + tmp92 + tmp98;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp135 + tmp236 + tmp238 + tmp240 + tmp242 + tmp244 + tmp39 + tmp41 + tmp432 + tmp436 + tmp440 + tmp441 + tmp490 + tmp491 + tmp492 + tmp493 + tmp61 + tmp68 + tmp70 + tmp71;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp114 + tmp165 + tmp166 + tmp167 + tmp168 + tmp169 + tmp170 + tmp171 + tmp172 + tmp20 + tmp73 + tmp74 + tmp75 + tmp76 + tmp79 + tmp80;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp145 + tmp146 + tmp148 + tmp15 + tmp189 + tmp190 + tmp192 + tmp193 + tmp2 + tmp243 + tmp246 + tmp406 + tmp407 + tmp408 + tmp409 + tmp5;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp174 + tmp176 + tmp184 + tmp24 + tmp260 + tmp267 + tmp339 + tmp340 + tmp341 + tmp342 + tmp344 + tmp345 + tmp416 + tmp417 + tmp506 + tmp507;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp21 + tmp258 + tmp266 + tmp274 + tmp337 + tmp398 + tmp422 + tmp424 + tmp428 + tmp430 + tmp447 + tmp449 + tmp496 + tmp497 + tmp498 + tmp499;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113 + tmp38 + tmp87;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp145 + tmp148 + tmp161 + tmp201 + tmp202 + tmp210 + tmp371 + tmp374 + tmp440 + tmp441 + tmp450 + tmp451 + tmp452 + tmp453 + tmp454 + tmp455 + tmp456 + tmp457 + tmp89 + tmp91;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=tmp215 + tmp221 + tmp227 + tmp260 + tmp267 + tmp288 + tmp304 + tmp312 + tmp317 + tmp351 + tmp352 + tmp353 + tmp354 + tmp355 + tmp356 + tmp357 + tmp358 + tmp359 + tmp360 + tmp361 + tmp362 + tmp363 + tmp76 + tmp79;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp166 + tmp169 + tmp172 + tmp196 + tmp197 + tmp198 + tmp199 + tmp20 + tmp200 + tmp21 + tmp73 + tmp74 + tmp75 + tmp77 + tmp80 + tmp82;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp36 + tmp37 + tmp38 + tmp39 + tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp176 + tmp24 + tmp269 + tmp274 + tmp339 + tmp340 + tmp342 + tmp343 + tmp344 + tmp347 + tmp394 + tmp395 + tmp416 + tmp417 + tmp418 + tmp419;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp112 + tmp12 + tmp123 + tmp13 + tmp141 + tmp142 + tmp143 + tmp146 + tmp147 + tmp149 + tmp16 + tmp277 + tmp278 + tmp279 + tmp280 + tmp281 + tmp282 + tmp6 + tmp92 + tmp98;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp110 + tmp113 + tmp135 + tmp136 + tmp137 + tmp138 + tmp139 + tmp15 + tmp87;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp114 + tmp184 + tmp225 + tmp232 + tmp329 + tmp330 + tmp332 + tmp334 + tmp335 + tmp337 + tmp338 + tmp421 + tmp464 + tmp465 + tmp504 + tmp505;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp135 + tmp234 + tmp235 + tmp236 + tmp237 + tmp238 + tmp239 + tmp240 + tmp241 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp39 + tmp41 + tmp44 + tmp49 + tmp61 + tmp71;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp114 + tmp120 + tmp167 + tmp170 + tmp198 + tmp20 + tmp200 + tmp24 + tmp443 + tmp444 + tmp73 + tmp74 + tmp75 + tmp80 + tmp81 + tmp83;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=tmp217 + tmp231 + tmp233 + tmp258 + tmp266 + tmp271 + tmp273 + tmp288 + tmp289 + tmp290 + tmp291 + tmp292 + tmp293 + tmp294 + tmp295 + tmp296 + tmp297 + tmp298 + tmp299 + tmp300 + tmp301 + tmp302 + tmp76 + tmp79;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp101 + tmp156 + tmp157 + tmp204 + tmp205 + tmp368 + tmp371 + tmp372 + tmp374 + tmp375 + tmp377 + tmp437 + tmp438 + tmp439 + tmp440 + tmp441 + tmp442 + tmp85 + tmp87 + tmp99;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp184 + tmp21 + tmp328 + tmp337 + tmp383 + tmp386 + tmp422 + tmp423 + tmp424 + tmp427 + tmp428 + tmp430 + tmp498 + tmp499 + tmp508 + tmp509;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp104 + tmp106 + tmp108 + tmp111 + tmp113 + tmp15 + tmp160 + tmp161 + tmp162 + tmp163 + tmp164 + tmp38;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp10 + tmp112 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131 + tmp132 + tmp133 + tmp134 + tmp14 + tmp3 + tmp68 + tmp70 + tmp9;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp166 + tmp175 + tmp176 + tmp178 + tmp179 + tmp180 + tmp183 + tmp187 + tmp270 + tmp272 + tmp274 + tmp284 + tmp285 + tmp364 + tmp365 + tmp366;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp20 + tmp21 + tmp24 + tmp34 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79 + tmp80 + tmp81 + tmp82 + tmp83;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp13 + tmp16 + tmp38 + tmp39 + tmp40 + tmp41 + tmp43 + tmp440 + tmp441 + tmp45 + tmp47 + tmp478 + tmp481 + tmp486 + tmp487 + tmp488 + tmp489 + tmp50 + tmp52 + tmp55;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp101 + tmp14 + tmp204 + tmp205 + tmp367 + tmp368 + tmp369 + tmp370 + tmp371 + tmp372 + tmp373 + tmp374 + tmp375 + tmp376 + tmp377 + tmp378 + tmp44 + tmp49 + tmp87 + tmp9;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=tmp179 + tmp183 + tmp198 + tmp200 + tmp214 + tmp215 + tmp216 + tmp217 + tmp218 + tmp219 + tmp220 + tmp221 + tmp222 + tmp223 + tmp224 + tmp225 + tmp226 + tmp227 + tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp135 + tmp137 + tmp139 + tmp160 + tmp161 + tmp164 + tmp471 + tmp473;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp114 + tmp274 + tmp312 + tmp317 + tmp329 + tmp332 + tmp335 + tmp337 + tmp338 + tmp399 + tmp401 + tmp446 + tmp462 + tmp463 + tmp464 + tmp465;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp166 + tmp175 + tmp176 + tmp177 + tmp178 + tmp180 + tmp181 + tmp184 + tmp187 + tmp271 + tmp273 + tmp283 + tmp284 + tmp285 + tmp286 + tmp287;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp1 + tmp10 + tmp11 + tmp12 + tmp15 + tmp152 + tmp153 + tmp154 + tmp155 + tmp156 + tmp157 + tmp158 + tmp159 + tmp17 + tmp3 + tmp4 + tmp51 + tmp54 + tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp1 + tmp127 + tmp131 + tmp141 + tmp146 + tmp15 + tmp153 + tmp154 + tmp188 + tmp189 + tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp68 + tmp70 + tmp92 + tmp98;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp166 + tmp176 + tmp184 + tmp283 + tmp339 + tmp340 + tmp341 + tmp342 + tmp343 + tmp344 + tmp345 + tmp346 + tmp347 + tmp348 + tmp349 + tmp350;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp114 + tmp274 + tmp337 + tmp383 + tmp386 + tmp422 + tmp424 + tmp426 + tmp428 + tmp429 + tmp430 + tmp445 + tmp446 + tmp447 + tmp448 + tmp449;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp104 + tmp106 + tmp107 + tmp109 + tmp112 + tmp113 + tmp135 + tmp161 + tmp482 + tmp483 + tmp484 + tmp485;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=tmp118 + tmp121 + tmp214 + tmp215 + tmp216 + tmp217 + tmp220 + tmp222 + tmp253 + tmp254 + tmp255 + tmp256 + tmp257 + tmp258 + tmp259 + tmp260 + tmp261 + tmp262 + tmp263 + tmp264 + tmp265 + tmp266 + tmp267 + tmp268;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp100 + tmp101 + tmp145 + tmp148 + tmp369 + tmp376 + tmp402 + tmp403 + tmp404 + tmp405 + tmp60 + tmp65 + tmp84 + tmp87 + tmp88 + tmp89 + tmp91 + tmp95 + tmp96 + tmp97;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp243 + tmp246 + tmp38 + tmp43 + tmp476 + tmp477 + tmp478 + tmp479 + tmp480 + tmp481 + tmp57 + tmp58 + tmp61 + tmp63 + tmp64 + tmp66 + tmp69 + tmp71 + tmp90 + tmp94;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp166 + tmp176 + tmp260 + tmp267 + tmp274 + tmp339 + tmp340 + tmp342 + tmp344 + tmp346 + tmp348 + tmp365 + tmp393 + tmp394 + tmp395 + tmp396;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp112 + tmp12 + tmp123 + tmp124 + tmp126 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147 + tmp148 + tmp149 + tmp150 + tmp151 + tmp51 + tmp54 + tmp6;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp104 + tmp106 + tmp113 + tmp136 + tmp138 + tmp15 + tmp161 + tmp38 + tmp472 + tmp475 + tmp482 + tmp483;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp184 + tmp21 + tmp312 + tmp317 + tmp327 + tmp328 + tmp329 + tmp330 + tmp331 + tmp332 + tmp333 + tmp334 + tmp335 + tmp336 + tmp337 + tmp338;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91 + tmp92 + tmp93 + tmp94 + tmp95 + tmp96 + tmp97 + tmp98 + tmp99;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=tmp217 + tmp225 + tmp232 + tmp26 + tmp265 + tmp268 + tmp288 + tmp289 + tmp29 + tmp290 + tmp293 + tmp295 + tmp308 + tmp313 + tmp343 + tmp347 + tmp358 + tmp359 + tmp410 + tmp411 + tmp412 + tmp413 + tmp414 + tmp415;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp20 + tmp22 + tmp24 + tmp25 + tmp28 + tmp30 + tmp32 + tmp35;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp13 + tmp135 + tmp16 + tmp237 + tmp238 + tmp245 + tmp319 + tmp320 + tmp321 + tmp322 + tmp323 + tmp324 + tmp325 + tmp326 + tmp45 + tmp55 + tmp57 + tmp60 + tmp64 + tmp65;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp114 + tmp184 + tmp258 + tmp266 + tmp337 + tmp420 + tmp421 + tmp422 + tmp423 + tmp424 + tmp425 + tmp426 + tmp427 + tmp428 + tmp429 + tmp430;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp104 + tmp106 + tmp113 + tmp135 + tmp15 + tmp162 + tmp163 + tmp470 + tmp474 + tmp484 + tmp485 + tmp87;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp10 + tmp112 + tmp123 + tmp125 + tmp127 + tmp128 + tmp130 + tmp131 + tmp132 + tmp156 + tmp157 + tmp243 + tmp246 + tmp278 + tmp279 + tmp3 + tmp500 + tmp501 + tmp502 + tmp503;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp175 + tmp176 + tmp178 + tmp180 + tmp182 + tmp185 + tmp187 + tmp24 + tmp269 + tmp270 + tmp271 + tmp272 + tmp273 + tmp274 + tmp275 + tmp276;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp38 + tmp42 + tmp43 + tmp53 + tmp56 + tmp57 + tmp58 + tmp59 + tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65 + tmp66 + tmp67 + tmp68 + tmp69 + tmp70 + tmp71;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp118 + tmp121 + tmp166 + tmp199 + tmp20 + tmp21 + tmp22 + tmp25 + tmp27 + tmp28 + tmp30 + tmp33 + tmp458 + tmp459 + tmp460 + tmp461;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=tmp179 + tmp183 + tmp215 + tmp255 + tmp26 + tmp261 + tmp288 + tmp29 + tmp298 + tmp300 + tmp304 + tmp316 + tmp318 + tmp351 + tmp354 + tmp355 + tmp383 + tmp386 + tmp387 + tmp388 + tmp389 + tmp390 + tmp391 + tmp392;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp100 + tmp14 + tmp161 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp208 + tmp209 + tmp210 + tmp211 + tmp212 + tmp213 + tmp88 + tmp9 + tmp90 + tmp94;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp104 + tmp106 + tmp112 + tmp113 + tmp38 + tmp470 + tmp471 + tmp472 + tmp473 + tmp474 + tmp475 + tmp87;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp21 + tmp225 + tmp232 + tmp274 + tmp329 + tmp332 + tmp333 + tmp335 + tmp336 + tmp337 + tmp338 + tmp397 + tmp398 + tmp399 + tmp400 + tmp401;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179 + tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp24;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1 + tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp114 + tmp117 + tmp119 + tmp166 + tmp171 + tmp20 + tmp22 + tmp25 + tmp26 + tmp28 + tmp29 + tmp30 + tmp460 + tmp461 + tmp494 + tmp495;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp135 + tmp238 + tmp320 + tmp324 + tmp325 + tmp326 + tmp431 + tmp432 + tmp433 + tmp434 + tmp435 + tmp436 + tmp45 + tmp51 + tmp54 + tmp55 + tmp57 + tmp64 + tmp90 + tmp94;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp100 + tmp156 + tmp157 + tmp161 + tmp201 + tmp204 + tmp205 + tmp207 + tmp208 + tmp209 + tmp211 + tmp247 + tmp248 + tmp249 + tmp250 + tmp251 + tmp252 + tmp60 + tmp65 + tmp88;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=tmp118 + tmp121 + tmp214 + tmp226 + tmp228 + tmp271 + tmp273 + tmp289 + tmp303 + tmp304 + tmp305 + tmp306 + tmp307 + tmp308 + tmp309 + tmp310 + tmp311 + tmp312 + tmp313 + tmp314 + tmp315 + tmp316 + tmp317 + tmp318;
+                                    }
+                                }
                             } else { // constant data
-                                const double wd0 = 4*d_p[0]*w7;
-                                EM_S[INDEX2(2,2,8)]+=4*wd0;
-                                EM_S[INDEX2(2,3,8)]+=2*wd0;
-                                EM_S[INDEX2(2,6,8)]+=2*wd0;
-                                EM_S[INDEX2(2,7,8)]+=  wd0;
-                                EM_S[INDEX2(3,2,8)]+=2*wd0;
-                                EM_S[INDEX2(3,3,8)]+=4*wd0;
-                                EM_S[INDEX2(3,6,8)]+=  wd0;
-                                EM_S[INDEX2(3,7,8)]+=2*wd0;
-                                EM_S[INDEX2(6,2,8)]+=2*wd0;
-                                EM_S[INDEX2(6,3,8)]+=  wd0;
-                                EM_S[INDEX2(6,6,8)]+=4*wd0;
-                                EM_S[INDEX2(6,7,8)]+=2*wd0;
-                                EM_S[INDEX2(7,2,8)]+=  wd0;
-                                EM_S[INDEX2(7,3,8)]+=2*wd0;
-                                EM_S[INDEX2(7,6,8)]+=2*wd0;
-                                EM_S[INDEX2(7,7,8)]+=4*wd0;
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double Aw00 = 8*A_p[INDEX4(k,0,m,0, numEq,3, numComp)]*w27;
+                                        const double Aw01 = 12*A_p[INDEX4(k,0,m,1, numEq,3, numComp)]*w8;
+                                        const double Aw02 = 12*A_p[INDEX4(k,0,m,2, numEq,3, numComp)]*w11;
+                                        const double Aw10 = 12*A_p[INDEX4(k,1,m,0, numEq,3, numComp)]*w8;
+                                        const double Aw11 = 8*A_p[INDEX4(k,1,m,1, numEq,3, numComp)]*w22;
+                                        const double Aw12 = 12*A_p[INDEX4(k,1,m,2, numEq,3, numComp)]*w10;
+                                        const double Aw20 = 12*A_p[INDEX4(k,2,m,0, numEq,3, numComp)]*w11;
+                                        const double Aw21 = 12*A_p[INDEX4(k,2,m,1, numEq,3, numComp)]*w10;
+                                        const double Aw22 = 8*A_p[INDEX4(k,2,m,2, numEq,3, numComp)]*w13;
+                                        const double tmp0 = Aw01 + Aw10;
+                                        const double tmp1 = Aw01 - Aw10;
+                                        const double tmp2 = Aw02 + Aw20;
+                                        const double tmp3 = Aw02 - Aw20;
+                                        const double tmp4 = Aw12 + Aw21;
+                                        const double tmp5 = Aw12 - Aw21;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp2 - 2*tmp4;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - tmp4 + 2*tmp1 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - 2*tmp1 + tmp2 - 2*tmp5;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 - 2*tmp0 + tmp3 - tmp5;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 + 2*tmp5 + tmp0;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - 2*tmp2 + tmp1 + tmp5;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp4 - tmp1 - tmp3;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 - tmp0 - tmp2;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 - 2*tmp1 - tmp4;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 - 2*tmp2 - 2*tmp4 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 - tmp5 - tmp3;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - tmp2 - 2*tmp5 + 2*tmp1;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp2 - tmp1 + tmp5;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp5 - tmp0 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 + tmp2 + tmp0;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 + tmp1 + 2*tmp4;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 + tmp2 + 2*tmp1;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp3 + 2*tmp0 + tmp5;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp4 + 2*tmp2 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp4 - 2*tmp1 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 - 2*tmp4 - tmp3;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp4 + tmp0 - tmp2;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 - tmp0 - 2*tmp5;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 - 2*tmp2 - tmp1;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 - tmp3 + tmp5 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 - 2*tmp1 - tmp2;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 + tmp4 + 2*tmp1;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 - 2*tmp2 + 2*tmp4;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp0 + tmp2 - tmp4;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 - tmp1 - 2*tmp4;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 + tmp1 + 2*tmp2;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 - 2*tmp5 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + tmp0 - 2*tmp5 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 + tmp1 + 2*tmp2;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 - tmp1 - 2*tmp4;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp0 + tmp2 - tmp4;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 - 2*tmp2 + 2*tmp4;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 + tmp4 + 2*tmp1;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 - 2*tmp1 - tmp2;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 - tmp3 + tmp5 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - tmp5 - 2*tmp2 - tmp1;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 - tmp0 - 2*tmp5;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 - tmp4 + tmp0 - tmp2;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp1 - 2*tmp4 - tmp3;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 + tmp4 - 2*tmp1 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp4 + 2*tmp2 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp3 + 2*tmp0 + tmp5;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 + 2*tmp5 + tmp2 + 2*tmp1;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + tmp3 + tmp1 + 2*tmp4;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 + tmp2 + tmp0;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 + 2*tmp5 - tmp0 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 + 2*tmp2 - tmp1 + tmp5;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - tmp2 - 2*tmp5 + 2*tmp1;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + 2*tmp0 - tmp5 - tmp3;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 - 2*tmp2 - 2*tmp4 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - 2*tmp3 - 2*tmp1 - tmp4;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=   Aw00 +   Aw11 +   Aw22 + tmp4 - tmp0 - tmp2;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  -Aw00 + 2*Aw11 + 2*Aw22 + 2*tmp4 - tmp1 - tmp3;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+= 2*Aw00 -   Aw11 + 2*Aw22 - 2*tmp2 + tmp1 + tmp5;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-2*Aw00 - 2*Aw11 + 4*Aw22 - 2*tmp3 + 2*tmp5 + tmp0;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+= 2*Aw00 + 2*Aw11 -   Aw22 + tmp3 - tmp5 - 2*tmp0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=-2*Aw00 + 4*Aw11 - 2*Aw22 - 2*tmp1 + tmp2 - 2*tmp5;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+= 4*Aw00 - 2*Aw11 - 2*Aw22 - tmp4 + 2*tmp1 + 2*tmp3;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=-4*Aw00 - 4*Aw11 - 4*Aw22 + 2*tmp0 + 2*tmp2 - 2*tmp4;
+                                    }
+                                }
                             }
                         }
                         ///////////////
-                        // process y //
+                        // process B //
                         ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                const double y_0 = y_p[0];
-                                const double y_1 = y_p[1];
-                                const double y_2 = y_p[2];
-                                const double y_3 = y_p[3];
-                                const double tmp0 = 6*w7*(y_1 + y_2);
-                                const double tmp1 = 6*w7*(y_0 + y_3);
-                                EM_F[2]+=tmp0 + 6*w5*y_3 + 6*w6*y_0;
-                                EM_F[3]+=tmp1 + 6*w5*y_2 + 6*w6*y_1;
-                                EM_F[6]+=tmp1 + 6*w5*y_1 + 6*w6*y_2;
-                                EM_F[7]+=tmp0 + 6*w5*y_0 + 6*w6*y_3;
+                        if (!B.isEmpty()) {
+                            const double* B_p=B.getSampleDataRO(e);
+                            if (B.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double B_0_0 = B_p[INDEX4(k,0,m,0, numEq,3,numComp)];
+                                        const double B_1_0 = B_p[INDEX4(k,1,m,0, numEq,3,numComp)];
+                                        const double B_2_0 = B_p[INDEX4(k,2,m,0, numEq,3,numComp)];
+                                        const double B_0_1 = B_p[INDEX4(k,0,m,1, numEq,3,numComp)];
+                                        const double B_1_1 = B_p[INDEX4(k,1,m,1, numEq,3,numComp)];
+                                        const double B_2_1 = B_p[INDEX4(k,2,m,1, numEq,3,numComp)];
+                                        const double B_0_2 = B_p[INDEX4(k,0,m,2, numEq,3,numComp)];
+                                        const double B_1_2 = B_p[INDEX4(k,1,m,2, numEq,3,numComp)];
+                                        const double B_2_2 = B_p[INDEX4(k,2,m,2, numEq,3,numComp)];
+                                        const double B_0_3 = B_p[INDEX4(k,0,m,3, numEq,3,numComp)];
+                                        const double B_1_3 = B_p[INDEX4(k,1,m,3, numEq,3,numComp)];
+                                        const double B_2_3 = B_p[INDEX4(k,2,m,3, numEq,3,numComp)];
+                                        const double B_0_4 = B_p[INDEX4(k,0,m,4, numEq,3,numComp)];
+                                        const double B_1_4 = B_p[INDEX4(k,1,m,4, numEq,3,numComp)];
+                                        const double B_2_4 = B_p[INDEX4(k,2,m,4, numEq,3,numComp)];
+                                        const double B_0_5 = B_p[INDEX4(k,0,m,5, numEq,3,numComp)];
+                                        const double B_1_5 = B_p[INDEX4(k,1,m,5, numEq,3,numComp)];
+                                        const double B_2_5 = B_p[INDEX4(k,2,m,5, numEq,3,numComp)];
+                                        const double B_0_6 = B_p[INDEX4(k,0,m,6, numEq,3,numComp)];
+                                        const double B_1_6 = B_p[INDEX4(k,1,m,6, numEq,3,numComp)];
+                                        const double B_2_6 = B_p[INDEX4(k,2,m,6, numEq,3,numComp)];
+                                        const double B_0_7 = B_p[INDEX4(k,0,m,7, numEq,3,numComp)];
+                                        const double B_1_7 = B_p[INDEX4(k,1,m,7, numEq,3,numComp)];
+                                        const double B_2_7 = B_p[INDEX4(k,2,m,7, numEq,3,numComp)];
+                                        const double tmp0 = w38*(B_2_1 + B_2_2);
+                                        const double tmp1 = w42*(B_1_3 + B_1_7);
+                                        const double tmp2 = w41*(B_0_3 + B_0_7);
+                                        const double tmp3 = w37*(B_1_1 + B_1_5);
+                                        const double tmp4 = w39*(B_0_2 + B_0_6);
+                                        const double tmp5 = w45*(B_2_5 + B_2_6);
+                                        const double tmp6 = w36*(B_0_1 + B_0_5);
+                                        const double tmp7 = w40*(B_1_2 + B_1_6);
+                                        const double tmp8 = w33*(B_0_0 + B_0_4);
+                                        const double tmp9 = w34*(B_1_0 + B_1_4);
+                                        const double tmp10 = w38*(B_2_4 + B_2_5 + B_2_6 + B_2_7);
+                                        const double tmp11 = w42*(-B_1_6 - B_1_7);
+                                        const double tmp12 = w41*(-B_0_5 - B_0_7);
+                                        const double tmp13 = w37*(-B_1_4 - B_1_5);
+                                        const double tmp14 = w39*(-B_0_4 - B_0_6);
+                                        const double tmp15 = w45*(B_2_0 + B_2_1 + B_2_2 + B_2_3);
+                                        const double tmp16 = w36*(-B_0_1 - B_0_3);
+                                        const double tmp17 = w40*(-B_1_2 - B_1_3);
+                                        const double tmp18 = w33*(-B_0_0 - B_0_2);
+                                        const double tmp19 = w34*(-B_1_0 - B_1_1);
+                                        const double tmp20 = w38*(-B_2_5 - B_2_7);
+                                        const double tmp21 = w35*(-B_2_4 - B_2_6);
+                                        const double tmp22 = w41*(B_0_1 + B_0_3);
+                                        const double tmp23 = w37*(-B_1_2 - B_1_7);
+                                        const double tmp24 = w39*(B_0_0 + B_0_2);
+                                        const double tmp25 = w45*(-B_2_0 - B_2_2);
+                                        const double tmp26 = w36*(B_0_5 + B_0_7);
+                                        const double tmp27 = w40*(-B_1_0 - B_1_5);
+                                        const double tmp28 = w33*(B_0_4 + B_0_6);
+                                        const double tmp29 = w46*(-B_2_1 - B_2_3);
+                                        const double tmp30 = w38*(B_2_0 + B_2_2);
+                                        const double tmp31 = w35*(B_2_1 + B_2_3);
+                                        const double tmp32 = w41*(-B_0_4 - B_0_6);
+                                        const double tmp33 = w37*(B_1_0 + B_1_5);
+                                        const double tmp34 = w39*(-B_0_5 - B_0_7);
+                                        const double tmp35 = w45*(B_2_5 + B_2_7);
+                                        const double tmp36 = w36*(-B_0_0 - B_0_2);
+                                        const double tmp37 = w40*(B_1_2 + B_1_7);
+                                        const double tmp38 = w33*(-B_0_1 - B_0_3);
+                                        const double tmp39 = w46*(B_2_4 + B_2_6);
+                                        const double tmp40 = w38*(-B_2_0 - B_2_1 - B_2_2 - B_2_3);
+                                        const double tmp41 = w42*(B_1_0 + B_1_1);
+                                        const double tmp42 = w41*(B_0_0 + B_0_2);
+                                        const double tmp43 = w37*(B_1_2 + B_1_3);
+                                        const double tmp44 = w39*(B_0_1 + B_0_3);
+                                        const double tmp45 = w45*(-B_2_4 - B_2_5 - B_2_6 - B_2_7);
+                                        const double tmp46 = w36*(B_0_4 + B_0_6);
+                                        const double tmp47 = w40*(B_1_4 + B_1_5);
+                                        const double tmp48 = w33*(B_0_5 + B_0_7);
+                                        const double tmp49 = w34*(B_1_6 + B_1_7);
+                                        const double tmp50 = w38*(B_2_0 + B_2_1);
+                                        const double tmp51 = w42*(-B_1_4 - B_1_5);
+                                        const double tmp52 = w35*(B_2_2 + B_2_3);
+                                        const double tmp53 = w37*(-B_1_6 - B_1_7);
+                                        const double tmp54 = w39*(B_0_0 + B_0_6);
+                                        const double tmp55 = w45*(B_2_6 + B_2_7);
+                                        const double tmp56 = w36*(B_0_1 + B_0_7);
+                                        const double tmp57 = w40*(-B_1_0 - B_1_1);
+                                        const double tmp58 = w46*(B_2_4 + B_2_5);
+                                        const double tmp59 = w34*(-B_1_2 - B_1_3);
+                                        const double tmp60 = w38*(-B_2_4 - B_2_5 - B_2_6 - B_2_7);
+                                        const double tmp61 = w37*(-B_1_2 - B_1_3 - B_1_6 - B_1_7);
+                                        const double tmp62 = w39*(-B_0_1 - B_0_3 - B_0_5 - B_0_7);
+                                        const double tmp63 = w45*(-B_2_0 - B_2_1 - B_2_2 - B_2_3);
+                                        const double tmp64 = w36*(-B_0_0 - B_0_2 - B_0_4 - B_0_6);
+                                        const double tmp65 = w40*(-B_1_0 - B_1_1 - B_1_4 - B_1_5);
+                                        const double tmp66 = w41*(B_0_4 + B_0_6);
+                                        const double tmp67 = w39*(B_0_5 + B_0_7);
+                                        const double tmp68 = w36*(B_0_0 + B_0_2);
+                                        const double tmp69 = w33*(B_0_1 + B_0_3);
+                                        const double tmp70 = w38*(-B_2_4 - B_2_7);
+                                        const double tmp71 = w42*(B_1_2 + B_1_6);
+                                        const double tmp72 = w41*(-B_0_2 - B_0_6);
+                                        const double tmp73 = w37*(B_1_0 + B_1_4);
+                                        const double tmp74 = w39*(-B_0_3 - B_0_7);
+                                        const double tmp75 = w45*(-B_2_0 - B_2_3);
+                                        const double tmp76 = w36*(-B_0_0 - B_0_4);
+                                        const double tmp77 = w40*(B_1_3 + B_1_7);
+                                        const double tmp78 = w33*(-B_0_1 - B_0_5);
+                                        const double tmp79 = w34*(B_1_1 + B_1_5);
+                                        const double tmp80 = w39*(B_0_0 + B_0_2 + B_0_4 + B_0_6);
+                                        const double tmp81 = w36*(B_0_1 + B_0_3 + B_0_5 + B_0_7);
+                                        const double tmp82 = w38*(B_2_0 + B_2_3);
+                                        const double tmp83 = w42*(-B_1_1 - B_1_5);
+                                        const double tmp84 = w41*(B_0_1 + B_0_5);
+                                        const double tmp85 = w37*(-B_1_3 - B_1_7);
+                                        const double tmp86 = w39*(B_0_0 + B_0_4);
+                                        const double tmp87 = w45*(B_2_4 + B_2_7);
+                                        const double tmp88 = w36*(B_0_3 + B_0_7);
+                                        const double tmp89 = w40*(-B_1_0 - B_1_4);
+                                        const double tmp90 = w33*(B_0_2 + B_0_6);
+                                        const double tmp91 = w34*(-B_1_2 - B_1_6);
+                                        const double tmp92 = w38*(-B_2_5 - B_2_6);
+                                        const double tmp93 = w45*(-B_2_1 - B_2_2);
+                                        const double tmp94 = w37*(B_1_0 + B_1_1 + B_1_4 + B_1_5);
+                                        const double tmp95 = w40*(B_1_2 + B_1_3 + B_1_6 + B_1_7);
+                                        const double tmp96 = w42*(-B_1_2 - B_1_3);
+                                        const double tmp97 = w41*(-B_0_1 - B_0_3);
+                                        const double tmp98 = w37*(-B_1_0 - B_1_1);
+                                        const double tmp99 = w39*(-B_0_0 - B_0_2);
+                                        const double tmp100 = w36*(-B_0_5 - B_0_7);
+                                        const double tmp101 = w40*(-B_1_6 - B_1_7);
+                                        const double tmp102 = w33*(-B_0_4 - B_0_6);
+                                        const double tmp103 = w34*(-B_1_4 - B_1_5);
+                                        const double tmp104 = w38*(B_2_6 + B_2_7);
+                                        const double tmp105 = w35*(B_2_4 + B_2_5);
+                                        const double tmp106 = w41*(B_0_2 + B_0_6);
+                                        const double tmp107 = w37*(B_1_2 + B_1_3 + B_1_6 + B_1_7);
+                                        const double tmp108 = w39*(B_0_3 + B_0_7);
+                                        const double tmp109 = w45*(B_2_0 + B_2_1);
+                                        const double tmp110 = w36*(B_0_0 + B_0_4);
+                                        const double tmp111 = w40*(B_1_0 + B_1_1 + B_1_4 + B_1_5);
+                                        const double tmp112 = w33*(B_0_1 + B_0_5);
+                                        const double tmp113 = w46*(B_2_2 + B_2_3);
+                                        const double tmp114 = w42*(-B_1_0 - B_1_4);
+                                        const double tmp115 = w41*(-B_0_0 - B_0_4);
+                                        const double tmp116 = w37*(-B_1_2 - B_1_6);
+                                        const double tmp117 = w39*(-B_0_1 - B_0_5);
+                                        const double tmp118 = w36*(-B_0_2 - B_0_6);
+                                        const double tmp119 = w40*(-B_1_1 - B_1_5);
+                                        const double tmp120 = w33*(-B_0_3 - B_0_7);
+                                        const double tmp121 = w34*(-B_1_3 - B_1_7);
+                                        const double tmp122 = w38*(B_2_2 + B_2_3);
+                                        const double tmp123 = w42*(B_1_6 + B_1_7);
+                                        const double tmp124 = w35*(B_2_0 + B_2_1);
+                                        const double tmp125 = w37*(B_1_4 + B_1_5);
+                                        const double tmp126 = w39*(-B_0_3 - B_0_5);
+                                        const double tmp127 = w45*(B_2_4 + B_2_5);
+                                        const double tmp128 = w36*(-B_0_2 - B_0_4);
+                                        const double tmp129 = w40*(B_1_2 + B_1_3);
+                                        const double tmp130 = w46*(B_2_6 + B_2_7);
+                                        const double tmp131 = w34*(B_1_0 + B_1_1);
+                                        const double tmp132 = w38*(-B_2_1 - B_2_2);
+                                        const double tmp133 = w37*(B_1_2 + B_1_7);
+                                        const double tmp134 = w39*(B_0_1 + B_0_7);
+                                        const double tmp135 = w36*(B_0_0 + B_0_6);
+                                        const double tmp136 = w40*(B_1_0 + B_1_5);
+                                        const double tmp137 = w45*(-B_2_5 - B_2_6);
+                                        const double tmp138 = w38*(-B_2_4 - B_2_6);
+                                        const double tmp139 = w35*(-B_2_5 - B_2_7);
+                                        const double tmp140 = w41*(-B_0_0 - B_0_2);
+                                        const double tmp141 = w37*(B_1_1 + B_1_4);
+                                        const double tmp142 = w39*(-B_0_1 - B_0_3);
+                                        const double tmp143 = w45*(-B_2_1 - B_2_3);
+                                        const double tmp144 = w36*(-B_0_4 - B_0_6);
+                                        const double tmp145 = w40*(B_1_3 + B_1_6);
+                                        const double tmp146 = w33*(-B_0_5 - B_0_7);
+                                        const double tmp147 = w46*(-B_2_0 - B_2_2);
+                                        const double tmp148 = w39*(B_0_2 + B_0_4);
+                                        const double tmp149 = w36*(B_0_3 + B_0_5);
+                                        const double tmp150 = w38*(B_2_5 + B_2_6);
+                                        const double tmp151 = w37*(-B_1_0 - B_1_5);
+                                        const double tmp152 = w39*(-B_0_0 - B_0_6);
+                                        const double tmp153 = w45*(B_2_1 + B_2_2);
+                                        const double tmp154 = w36*(-B_0_1 - B_0_7);
+                                        const double tmp155 = w40*(-B_1_2 - B_1_7);
+                                        const double tmp156 = w41*(-B_0_3 - B_0_7);
+                                        const double tmp157 = w39*(-B_0_2 - B_0_6);
+                                        const double tmp158 = w36*(-B_0_1 - B_0_5);
+                                        const double tmp159 = w33*(-B_0_0 - B_0_4);
+                                        const double tmp160 = w38*(-B_2_2 - B_2_3);
+                                        const double tmp161 = w35*(-B_2_0 - B_2_1);
+                                        const double tmp162 = w45*(-B_2_4 - B_2_5);
+                                        const double tmp163 = w46*(-B_2_6 - B_2_7);
+                                        const double tmp164 = w38*(-B_2_0 - B_2_3);
+                                        const double tmp165 = w37*(B_1_3 + B_1_6);
+                                        const double tmp166 = w40*(B_1_1 + B_1_4);
+                                        const double tmp167 = w45*(-B_2_4 - B_2_7);
+                                        const double tmp168 = w39*(B_0_3 + B_0_5);
+                                        const double tmp169 = w36*(B_0_2 + B_0_4);
+                                        const double tmp170 = w38*(B_2_1 + B_2_3);
+                                        const double tmp171 = w35*(B_2_0 + B_2_2);
+                                        const double tmp172 = w41*(B_0_5 + B_0_7);
+                                        const double tmp173 = w37*(-B_1_3 - B_1_6);
+                                        const double tmp174 = w39*(B_0_4 + B_0_6);
+                                        const double tmp175 = w45*(B_2_4 + B_2_6);
+                                        const double tmp176 = w36*(B_0_1 + B_0_3);
+                                        const double tmp177 = w40*(-B_1_1 - B_1_4);
+                                        const double tmp178 = w33*(B_0_0 + B_0_2);
+                                        const double tmp179 = w46*(B_2_5 + B_2_7);
+                                        const double tmp180 = w38*(B_2_5 + B_2_7);
+                                        const double tmp181 = w42*(-B_1_3 - B_1_7);
+                                        const double tmp182 = w35*(B_2_4 + B_2_6);
+                                        const double tmp183 = w37*(-B_1_1 - B_1_5);
+                                        const double tmp184 = w39*(B_0_1 + B_0_3 + B_0_5 + B_0_7);
+                                        const double tmp185 = w45*(B_2_0 + B_2_2);
+                                        const double tmp186 = w36*(B_0_0 + B_0_2 + B_0_4 + B_0_6);
+                                        const double tmp187 = w40*(-B_1_2 - B_1_6);
+                                        const double tmp188 = w46*(B_2_1 + B_2_3);
+                                        const double tmp189 = w34*(-B_1_0 - B_1_4);
+                                        const double tmp190 = w38*(B_2_4 + B_2_5);
+                                        const double tmp191 = w35*(B_2_6 + B_2_7);
+                                        const double tmp192 = w41*(-B_0_1 - B_0_5);
+                                        const double tmp193 = w37*(-B_1_0 - B_1_1 - B_1_4 - B_1_5);
+                                        const double tmp194 = w39*(-B_0_0 - B_0_4);
+                                        const double tmp195 = w45*(B_2_2 + B_2_3);
+                                        const double tmp196 = w36*(-B_0_3 - B_0_7);
+                                        const double tmp197 = w40*(-B_1_2 - B_1_3 - B_1_6 - B_1_7);
+                                        const double tmp198 = w33*(-B_0_2 - B_0_6);
+                                        const double tmp199 = w46*(B_2_0 + B_2_1);
+                                        const double tmp200 = w38*(-B_2_6 - B_2_7);
+                                        const double tmp201 = w42*(B_1_2 + B_1_3);
+                                        const double tmp202 = w35*(-B_2_4 - B_2_5);
+                                        const double tmp203 = w37*(B_1_0 + B_1_1);
+                                        const double tmp204 = w45*(-B_2_0 - B_2_1);
+                                        const double tmp205 = w40*(B_1_6 + B_1_7);
+                                        const double tmp206 = w46*(-B_2_2 - B_2_3);
+                                        const double tmp207 = w34*(B_1_4 + B_1_5);
+                                        const double tmp208 = w37*(-B_1_1 - B_1_4);
+                                        const double tmp209 = w39*(-B_0_2 - B_0_4);
+                                        const double tmp210 = w36*(-B_0_3 - B_0_5);
+                                        const double tmp211 = w40*(-B_1_3 - B_1_6);
+                                        const double tmp212 = w38*(B_2_4 + B_2_7);
+                                        const double tmp213 = w45*(B_2_0 + B_2_3);
+                                        const double tmp214 = w41*(B_0_0 + B_0_4);
+                                        const double tmp215 = w39*(B_0_1 + B_0_5);
+                                        const double tmp216 = w36*(B_0_2 + B_0_6);
+                                        const double tmp217 = w33*(B_0_3 + B_0_7);
+                                        const double tmp218 = w42*(B_1_1 + B_1_5);
+                                        const double tmp219 = w37*(B_1_3 + B_1_7);
+                                        const double tmp220 = w40*(B_1_0 + B_1_4);
+                                        const double tmp221 = w34*(B_1_2 + B_1_6);
+                                        const double tmp222 = w39*(-B_0_1 - B_0_7);
+                                        const double tmp223 = w36*(-B_0_0 - B_0_6);
+                                        const double tmp224 = w38*(-B_2_0 - B_2_1);
+                                        const double tmp225 = w35*(-B_2_2 - B_2_3);
+                                        const double tmp226 = w45*(-B_2_6 - B_2_7);
+                                        const double tmp227 = w46*(-B_2_4 - B_2_5);
+                                        const double tmp228 = w38*(B_2_4 + B_2_6);
+                                        const double tmp229 = w42*(B_1_0 + B_1_4);
+                                        const double tmp230 = w35*(B_2_5 + B_2_7);
+                                        const double tmp231 = w37*(B_1_2 + B_1_6);
+                                        const double tmp232 = w39*(-B_0_0 - B_0_2 - B_0_4 - B_0_6);
+                                        const double tmp233 = w45*(B_2_1 + B_2_3);
+                                        const double tmp234 = w36*(-B_0_1 - B_0_3 - B_0_5 - B_0_7);
+                                        const double tmp235 = w40*(B_1_1 + B_1_5);
+                                        const double tmp236 = w46*(B_2_0 + B_2_2);
+                                        const double tmp237 = w34*(B_1_3 + B_1_7);
+                                        const double tmp238 = w42*(-B_1_2 - B_1_6);
+                                        const double tmp239 = w37*(-B_1_0 - B_1_4);
+                                        const double tmp240 = w40*(-B_1_3 - B_1_7);
+                                        const double tmp241 = w34*(-B_1_1 - B_1_5);
+                                        const double tmp242 = w38*(-B_2_4 - B_2_5);
+                                        const double tmp243 = w42*(-B_1_0 - B_1_1);
+                                        const double tmp244 = w35*(-B_2_6 - B_2_7);
+                                        const double tmp245 = w37*(-B_1_2 - B_1_3);
+                                        const double tmp246 = w45*(-B_2_2 - B_2_3);
+                                        const double tmp247 = w40*(-B_1_4 - B_1_5);
+                                        const double tmp248 = w46*(-B_2_0 - B_2_1);
+                                        const double tmp249 = w34*(-B_1_6 - B_1_7);
+                                        const double tmp250 = w42*(B_1_4 + B_1_5);
+                                        const double tmp251 = w37*(B_1_6 + B_1_7);
+                                        const double tmp252 = w40*(B_1_0 + B_1_1);
+                                        const double tmp253 = w34*(B_1_2 + B_1_3);
+                                        const double tmp254 = w38*(-B_2_1 - B_2_3);
+                                        const double tmp255 = w35*(-B_2_0 - B_2_2);
+                                        const double tmp256 = w45*(-B_2_4 - B_2_6);
+                                        const double tmp257 = w46*(-B_2_5 - B_2_7);
+                                        const double tmp258 = w38*(B_2_0 + B_2_1 + B_2_2 + B_2_3);
+                                        const double tmp259 = w45*(B_2_4 + B_2_5 + B_2_6 + B_2_7);
+                                        const double tmp260 = w38*(-B_2_0 - B_2_2);
+                                        const double tmp261 = w35*(-B_2_1 - B_2_3);
+                                        const double tmp262 = w45*(-B_2_5 - B_2_7);
+                                        const double tmp263 = w46*(-B_2_4 - B_2_6);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-B_0_0*w50 - B_0_1*w41 - B_0_6*w33 - B_0_7*w49 + B_1_0*w47 - B_1_2*w42 - B_1_5*w34 + B_1_7*w48 - B_2_0*w43 - B_2_3*w35 - B_2_4*w46 - B_2_7*w44 + tmp132 + tmp137 + tmp208 + tmp209 + tmp210 + tmp211;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-B_0_0*w41 - B_0_1*w50 - B_0_6*w49 - B_0_7*w33 + tmp126 + tmp128 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-B_1_0*w42 + B_1_2*w47 + B_1_5*w48 - B_1_7*w34 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp146 + tmp147 + tmp173 + tmp177;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp40 + tmp45 + tmp96 + tmp97 + tmp98 + tmp99;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-B_2_0*w46 - B_2_3*w44 - B_2_4*w43 - B_2_7*w35 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp192 + tmp193 + tmp194 + tmp196 + tmp197 + tmp198 + tmp224 + tmp225 + tmp226 + tmp227;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp232 + tmp234 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=B_0_0*w50 + B_0_1*w41 + B_0_6*w33 + B_0_7*w49 + tmp148 + tmp149 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=B_0_0*w41 + B_0_1*w50 + B_0_6*w49 + B_0_7*w33 + B_1_1*w47 - B_1_3*w42 - B_1_4*w34 + B_1_6*w48 - B_2_1*w43 - B_2_2*w35 - B_2_5*w46 - B_2_6*w44 + tmp151 + tmp155 + tmp164 + tmp167 + tmp168 + tmp169;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp101 + tmp103 + tmp40 + tmp42 + tmp44 + tmp45 + tmp46 + tmp48 + tmp96 + tmp98;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-B_1_1*w42 + B_1_3*w47 + B_1_4*w48 - B_1_6*w34 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp193 + tmp197 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-B_2_1*w46 - B_2_2*w44 - B_2_5*w43 - B_2_6*w35 + tmp70 + tmp75 + tmp83 + tmp84 + tmp85 + tmp86 + tmp88 + tmp89 + tmp90 + tmp91;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp60 + tmp61 + tmp63 + tmp65 + tmp80 + tmp81;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp181 + tmp183 + tmp184 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-B_1_0*w47 + B_1_2*w42 + B_1_5*w34 - B_1_7*w48 + tmp138 + tmp139 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp100 + tmp102 + tmp40 + tmp41 + tmp43 + tmp45 + tmp47 + tmp49 + tmp97 + tmp99;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-B_0_2*w50 - B_0_3*w41 - B_0_4*w33 - B_0_5*w49 + B_1_0*w42 - B_1_2*w47 - B_1_5*w48 + B_1_7*w34 - B_2_1*w35 - B_2_2*w43 - B_2_5*w44 - B_2_6*w46 + tmp152 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-B_0_2*w41 - B_0_3*w50 - B_0_4*w49 - B_0_5*w33 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp229 + tmp231 + tmp232 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp60 + tmp62 + tmp63 + tmp64 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-B_2_1*w44 - B_2_2*w46 - B_2_5*w35 - B_2_6*w43 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp107 + tmp111 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-B_1_1*w47 + B_1_3*w42 + B_1_4*w34 - B_1_6*w48 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp28 + tmp29 + tmp33 + tmp37;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=B_0_2*w50 + B_0_3*w41 + B_0_4*w33 + B_0_5*w49 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp54 + tmp56;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=B_0_2*w41 + B_0_3*w50 + B_0_4*w49 + B_0_5*w33 + B_1_1*w42 - B_1_3*w47 - B_1_4*w48 + B_1_6*w34 - B_2_0*w35 - B_2_3*w43 - B_2_4*w44 - B_2_7*w46 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp60 + tmp63 + tmp80 + tmp81 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp184 + tmp186 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp106 + tmp107 + tmp108 + tmp110 + tmp111 + tmp112 + tmp160 + tmp161 + tmp162 + tmp163;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-B_2_0*w44 - B_2_3*w46 - B_2_4*w35 - B_2_7*w43 + tmp1 + tmp2 + tmp3 + tmp4 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=B_2_0*w43 + B_2_3*w35 + B_2_4*w46 + B_2_7*w44 + tmp0 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp5;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp228 + tmp230 + tmp232 + tmp233 + tmp234 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp62 + tmp64 + tmp65;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-B_0_2*w33 - B_0_3*w49 - B_0_4*w50 - B_0_5*w41 - B_1_1*w34 + B_1_3*w48 + B_1_4*w47 - B_1_6*w42 + B_2_0*w46 + B_2_3*w44 + B_2_4*w43 + B_2_7*w35 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-B_0_2*w49 - B_0_3*w33 - B_0_4*w41 - B_0_5*w50 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp55 + tmp57 + tmp58 + tmp59;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=B_1_1*w48 - B_1_3*w34 - B_1_4*w42 + B_1_6*w47 + tmp23 + tmp27 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp38 + tmp39;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp190 + tmp191 + tmp193 + tmp195 + tmp197 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=B_2_1*w43 + B_2_2*w35 + B_2_5*w46 + B_2_6*w44 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp65 + tmp80 + tmp81;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=B_0_2*w33 + B_0_3*w49 + B_0_4*w50 + B_0_5*w41 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=B_0_2*w49 + B_0_3*w33 + B_0_4*w41 + B_0_5*w50 - B_1_0*w34 + B_1_2*w48 + B_1_5*w47 - B_1_7*w42 + B_2_1*w46 + B_2_2*w44 + B_2_5*w43 + B_2_6*w35 + tmp134 + tmp135 + tmp208 + tmp211 + tmp212 + tmp213;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp10 + tmp11 + tmp13 + tmp15 + tmp17 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=B_1_0*w48 - B_1_2*w34 - B_1_5*w42 + B_1_7*w47 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233 + tmp234 + tmp235 + tmp236 + tmp237;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp258 + tmp259 + tmp62 + tmp64 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=B_2_1*w35 + B_2_2*w43 + B_2_5*w44 + B_2_6*w46 + tmp71 + tmp72 + tmp73 + tmp74 + tmp76 + tmp77 + tmp78 + tmp79 + tmp82 + tmp87;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp104 + tmp105 + tmp107 + tmp109 + tmp111 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=B_1_1*w34 - B_1_3*w48 - B_1_4*w47 + B_1_6*w42 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp10 + tmp12 + tmp14 + tmp15 + tmp16 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-B_0_0*w33 - B_0_1*w49 - B_0_6*w50 - B_0_7*w41 - B_1_1*w48 + B_1_3*w34 + B_1_4*w42 - B_1_6*w47 + B_2_1*w44 + B_2_2*w46 + B_2_5*w35 + B_2_6*w43 + tmp133 + tmp136 + tmp209 + tmp210 + tmp212 + tmp213;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-B_0_0*w49 - B_0_1*w33 - B_0_6*w41 - B_0_7*w50 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp258 + tmp259 + tmp80 + tmp81 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp180 + tmp182 + tmp184 + tmp185 + tmp186 + tmp188 + tmp218 + tmp219 + tmp220 + tmp221;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=B_2_0*w35 + B_2_3*w43 + B_2_4*w44 + B_2_7*w46 + tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp10 + tmp15 + tmp250 + tmp251 + tmp252 + tmp253 + tmp66 + tmp67 + tmp68 + tmp69;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=B_1_0*w34 - B_1_2*w48 - B_1_5*w47 + B_1_7*w42 + tmp141 + tmp145 + tmp170 + tmp171 + tmp172 + tmp174 + tmp175 + tmp176 + tmp178 + tmp179;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=B_0_0*w33 + B_0_1*w49 + B_0_6*w50 + B_0_7*w41 + tmp122 + tmp123 + tmp124 + tmp125 + tmp127 + tmp129 + tmp130 + tmp131 + tmp148 + tmp149;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=B_0_0*w49 + B_0_1*w33 + B_0_6*w41 + B_0_7*w50 - B_1_0*w48 + B_1_2*w34 + B_1_5*w42 - B_1_7*w47 + B_2_0*w44 + B_2_3*w46 + B_2_4*w35 + B_2_7*w43 + tmp150 + tmp153 + tmp165 + tmp166 + tmp168 + tmp169;
+                                    }
+                                }
                             } else { // constant data
-                                EM_F[2]+=36*w7*y_p[0];
-                                EM_F[3]+=36*w7*y_p[0];
-                                EM_F[6]+=36*w7*y_p[0];
-                                EM_F[7]+=36*w7*y_p[0];
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double wB0 = B_p[INDEX3(k,0,m,numEq,3)]*w55;
+                                        const double wB1 = B_p[INDEX3(k,1,m,numEq,3)]*w56;
+                                        const double wB2 = B_p[INDEX3(k,2,m,numEq,3)]*w54;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+= 4*wB0 + 4*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+= 4*wB0 + 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+= 2*wB0 + 4*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+= 2*wB0 + 2*wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+= 2*wB0 + 2*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+= 2*wB0 +   wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=   wB0 + 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=   wB0 +   wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-4*wB0 + 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=-4*wB0 + 4*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=-2*wB0 + 2*wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-2*wB0 + 4*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=-2*wB0 +   wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-2*wB0 + 2*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=  -wB0 +   wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  -wB0 + 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+= 2*wB0 - 4*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+= 2*wB0 - 2*wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+= 4*wB0 - 4*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+= 4*wB0 - 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=   wB0 - 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=   wB0 -   wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+= 2*wB0 - 2*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+= 2*wB0 -   wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=-2*wB0 - 2*wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-2*wB0 - 4*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-4*wB0 - 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=-4*wB0 - 4*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=  -wB0 -   wB1 +   wB2;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  -wB0 - 2*wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=-2*wB0 -   wB1 + 2*wB2;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-2*wB0 - 2*wB1 + 4*wB2;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+= 2*wB0 + 2*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+= 2*wB0 +   wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=   wB0 + 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=   wB0 +   wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+= 4*wB0 + 4*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+= 4*wB0 + 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+= 2*wB0 + 4*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+= 2*wB0 + 2*wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=-2*wB0 +   wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-2*wB0 + 2*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=  -wB0 +   wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  -wB0 + 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-4*wB0 + 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=-4*wB0 + 4*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=-2*wB0 + 2*wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=-2*wB0 + 4*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=   wB0 - 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=   wB0 -   wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+= 2*wB0 - 2*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+= 2*wB0 -   wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+= 2*wB0 - 4*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+= 2*wB0 - 2*wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+= 4*wB0 - 4*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+= 4*wB0 - 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=  -wB0 -   wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  -wB0 - 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=-2*wB0 -   wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-2*wB0 - 2*wB1 - 4*wB2;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=-2*wB0 - 2*wB1 -   wB2;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=-2*wB0 - 4*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-4*wB0 - 2*wB1 - 2*wB2;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=-4*wB0 - 4*wB1 - 4*wB2;
+                                    }
+                                }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // k0 loop
-                } // k2 loop
-            } // colouring
-        } // face 3
-
-        if (domain->m_faceOffset[4] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
                         ///////////////
-                        // process d //
+                        // process C //
                         ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                const double d_0 = d_p[0];
-                                const double d_1 = d_p[1];
-                                const double d_2 = d_p[2];
-                                const double d_3 = d_p[3];
-                                const double tmp0 = w10*(d_0 + d_2);
-                                const double tmp1 = w11*(d_1 + d_3);
-                                const double tmp2 = w12*(d_0 + d_1 + d_2 + d_3);
-                                const double tmp3 = w12*(d_1 + d_2);
-                                const double tmp4 = w10*(d_1 + d_3);
-                                const double tmp5 = w11*(d_0 + d_2);
-                                const double tmp6 = w12*(d_0 + d_3);
-                                const double tmp7 = w10*(d_0 + d_1);
-                                const double tmp8 = w11*(d_2 + d_3);
-                                const double tmp9 = w10*(d_2 + d_3);
-                                const double tmp10 = w11*(d_0 + d_1);
-                                EM_S[INDEX2(0,0,8)]+=d_0*w14 + d_3*w13 + tmp3;
-                                EM_S[INDEX2(0,1,8)]+=tmp10 + tmp9;
-                                EM_S[INDEX2(0,2,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(0,3,8)]+=tmp2;
-                                EM_S[INDEX2(1,0,8)]+=tmp10 + tmp9;
-                                EM_S[INDEX2(1,1,8)]+=d_1*w14 + d_2*w13 + tmp6;
-                                EM_S[INDEX2(1,2,8)]+=tmp2;
-                                EM_S[INDEX2(1,3,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(2,0,8)]+=tmp4 + tmp5;
-                                EM_S[INDEX2(2,1,8)]+=tmp2;
-                                EM_S[INDEX2(2,2,8)]+=d_1*w13 + d_2*w14 + tmp6;
-                                EM_S[INDEX2(2,3,8)]+=tmp7 + tmp8;
-                                EM_S[INDEX2(3,0,8)]+=tmp2;
-                                EM_S[INDEX2(3,1,8)]+=tmp0 + tmp1;
-                                EM_S[INDEX2(3,2,8)]+=tmp7 + tmp8;
-                                EM_S[INDEX2(3,3,8)]+=d_0*w13 + d_3*w14 + tmp3;
+                        if (!C.isEmpty()) {
+                            const double* C_p=C.getSampleDataRO(e);
+                            if (C.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double C_0_0 = C_p[INDEX4(k,m,0, 0, numEq,numComp,3)];
+                                        const double C_1_0 = C_p[INDEX4(k,m,1, 0, numEq,numComp,3)];
+                                        const double C_2_0 = C_p[INDEX4(k,m,2, 0, numEq,numComp,3)];
+                                        const double C_0_1 = C_p[INDEX4(k,m,0, 1, numEq,numComp,3)];
+                                        const double C_1_1 = C_p[INDEX4(k,m,1, 1, numEq,numComp,3)];
+                                        const double C_2_1 = C_p[INDEX4(k,m,2, 1, numEq,numComp,3)];
+                                        const double C_0_2 = C_p[INDEX4(k,m,0, 2, numEq,numComp,3)];
+                                        const double C_1_2 = C_p[INDEX4(k,m,1, 2, numEq,numComp,3)];
+                                        const double C_2_2 = C_p[INDEX4(k,m,2, 2, numEq,numComp,3)];
+                                        const double C_0_3 = C_p[INDEX4(k,m,0, 3, numEq,numComp,3)];
+                                        const double C_1_3 = C_p[INDEX4(k,m,1, 3, numEq,numComp,3)];
+                                        const double C_2_3 = C_p[INDEX4(k,m,2, 3, numEq,numComp,3)];
+                                        const double C_0_4 = C_p[INDEX4(k,m,0, 4, numEq,numComp,3)];
+                                        const double C_1_4 = C_p[INDEX4(k,m,1, 4, numEq,numComp,3)];
+                                        const double C_2_4 = C_p[INDEX4(k,m,2, 4, numEq,numComp,3)];
+                                        const double C_0_5 = C_p[INDEX4(k,m,0, 5, numEq,numComp,3)];
+                                        const double C_1_5 = C_p[INDEX4(k,m,1, 5, numEq,numComp,3)];
+                                        const double C_2_5 = C_p[INDEX4(k,m,2, 5, numEq,numComp,3)];
+                                        const double C_0_6 = C_p[INDEX4(k,m,0, 6, numEq,numComp,3)];
+                                        const double C_1_6 = C_p[INDEX4(k,m,1, 6, numEq,numComp,3)];
+                                        const double C_2_6 = C_p[INDEX4(k,m,2, 6, numEq,numComp,3)];
+                                        const double C_0_7 = C_p[INDEX4(k,m,0, 7, numEq,numComp,3)];
+                                        const double C_1_7 = C_p[INDEX4(k,m,1, 7, numEq,numComp,3)];
+                                        const double C_2_7 = C_p[INDEX4(k,m,2, 7, numEq,numComp,3)];
+                                        const double tmp0 = w38*(-C_2_5 - C_2_6);
+                                        const double tmp1 = w42*(C_1_3 + C_1_7);
+                                        const double tmp2 = w41*(C_0_3 + C_0_7);
+                                        const double tmp3 = w37*(C_1_1 + C_1_5);
+                                        const double tmp4 = w39*(C_0_2 + C_0_6);
+                                        const double tmp5 = w45*(-C_2_1 - C_2_2);
+                                        const double tmp6 = w36*(C_0_1 + C_0_5);
+                                        const double tmp7 = w40*(C_1_2 + C_1_6);
+                                        const double tmp8 = w33*(C_0_0 + C_0_4);
+                                        const double tmp9 = w34*(C_1_0 + C_1_4);
+                                        const double tmp10 = w38*(C_2_4 + C_2_5 + C_2_6 + C_2_7);
+                                        const double tmp11 = w42*(C_1_4 + C_1_5);
+                                        const double tmp12 = w41*(C_0_4 + C_0_6);
+                                        const double tmp13 = w37*(C_1_6 + C_1_7);
+                                        const double tmp14 = w39*(C_0_5 + C_0_7);
+                                        const double tmp15 = w45*(C_2_0 + C_2_1 + C_2_2 + C_2_3);
+                                        const double tmp16 = w36*(C_0_0 + C_0_2);
+                                        const double tmp17 = w40*(C_1_0 + C_1_1);
+                                        const double tmp18 = w33*(C_0_1 + C_0_3);
+                                        const double tmp19 = w34*(C_1_2 + C_1_3);
+                                        const double tmp20 = w38*(-C_2_5 - C_2_7);
+                                        const double tmp21 = w35*(-C_2_4 - C_2_6);
+                                        const double tmp22 = w41*(C_0_1 + C_0_3);
+                                        const double tmp23 = w37*(C_1_0 + C_1_5);
+                                        const double tmp24 = w39*(C_0_0 + C_0_2);
+                                        const double tmp25 = w45*(-C_2_0 - C_2_2);
+                                        const double tmp26 = w36*(C_0_5 + C_0_7);
+                                        const double tmp27 = w40*(C_1_2 + C_1_7);
+                                        const double tmp28 = w33*(C_0_4 + C_0_6);
+                                        const double tmp29 = w46*(-C_2_1 - C_2_3);
+                                        const double tmp30 = w38*(C_2_0 + C_2_2);
+                                        const double tmp31 = w35*(C_2_1 + C_2_3);
+                                        const double tmp32 = w41*(-C_0_4 - C_0_6);
+                                        const double tmp33 = w37*(-C_1_2 - C_1_7);
+                                        const double tmp34 = w39*(-C_0_5 - C_0_7);
+                                        const double tmp35 = w45*(C_2_5 + C_2_7);
+                                        const double tmp36 = w36*(-C_0_0 - C_0_2);
+                                        const double tmp37 = w40*(-C_1_0 - C_1_5);
+                                        const double tmp38 = w33*(-C_0_1 - C_0_3);
+                                        const double tmp39 = w46*(C_2_4 + C_2_6);
+                                        const double tmp40 = w38*(-C_2_0 - C_2_1 - C_2_2 - C_2_3);
+                                        const double tmp41 = w42*(-C_1_2 - C_1_3);
+                                        const double tmp42 = w41*(-C_0_1 - C_0_3);
+                                        const double tmp43 = w37*(-C_1_0 - C_1_1);
+                                        const double tmp44 = w39*(-C_0_0 - C_0_2);
+                                        const double tmp45 = w45*(-C_2_4 - C_2_5 - C_2_6 - C_2_7);
+                                        const double tmp46 = w36*(-C_0_5 - C_0_7);
+                                        const double tmp47 = w40*(-C_1_6 - C_1_7);
+                                        const double tmp48 = w33*(-C_0_4 - C_0_6);
+                                        const double tmp49 = w34*(-C_1_4 - C_1_5);
+                                        const double tmp50 = w38*(C_2_0 + C_2_1);
+                                        const double tmp51 = w42*(-C_1_4 - C_1_5);
+                                        const double tmp52 = w35*(C_2_2 + C_2_3);
+                                        const double tmp53 = w37*(-C_1_6 - C_1_7);
+                                        const double tmp54 = w39*(-C_0_1 - C_0_7);
+                                        const double tmp55 = w45*(C_2_6 + C_2_7);
+                                        const double tmp56 = w36*(-C_0_0 - C_0_6);
+                                        const double tmp57 = w40*(-C_1_0 - C_1_1);
+                                        const double tmp58 = w46*(C_2_4 + C_2_5);
+                                        const double tmp59 = w34*(-C_1_2 - C_1_3);
+                                        const double tmp60 = w38*(C_2_0 + C_2_1 + C_2_2 + C_2_3);
+                                        const double tmp61 = w37*(C_1_0 + C_1_1 + C_1_4 + C_1_5);
+                                        const double tmp62 = w39*(C_0_0 + C_0_2 + C_0_4 + C_0_6);
+                                        const double tmp63 = w45*(C_2_4 + C_2_5 + C_2_6 + C_2_7);
+                                        const double tmp64 = w36*(C_0_1 + C_0_3 + C_0_5 + C_0_7);
+                                        const double tmp65 = w40*(C_1_2 + C_1_3 + C_1_6 + C_1_7);
+                                        const double tmp66 = w41*(-C_0_5 - C_0_7);
+                                        const double tmp67 = w39*(-C_0_4 - C_0_6);
+                                        const double tmp68 = w36*(-C_0_1 - C_0_3);
+                                        const double tmp69 = w33*(-C_0_0 - C_0_2);
+                                        const double tmp70 = w38*(C_2_0 + C_2_3);
+                                        const double tmp71 = w42*(C_1_2 + C_1_6);
+                                        const double tmp72 = w41*(-C_0_2 - C_0_6);
+                                        const double tmp73 = w37*(C_1_0 + C_1_4);
+                                        const double tmp74 = w39*(-C_0_3 - C_0_7);
+                                        const double tmp75 = w45*(C_2_4 + C_2_7);
+                                        const double tmp76 = w36*(-C_0_0 - C_0_4);
+                                        const double tmp77 = w40*(C_1_3 + C_1_7);
+                                        const double tmp78 = w33*(-C_0_1 - C_0_5);
+                                        const double tmp79 = w34*(C_1_1 + C_1_5);
+                                        const double tmp80 = w39*(-C_0_1 - C_0_3 - C_0_5 - C_0_7);
+                                        const double tmp81 = w36*(-C_0_0 - C_0_2 - C_0_4 - C_0_6);
+                                        const double tmp82 = w38*(-C_2_4 - C_2_7);
+                                        const double tmp83 = w42*(-C_1_1 - C_1_5);
+                                        const double tmp84 = w41*(C_0_1 + C_0_5);
+                                        const double tmp85 = w37*(-C_1_3 - C_1_7);
+                                        const double tmp86 = w39*(C_0_0 + C_0_4);
+                                        const double tmp87 = w45*(-C_2_0 - C_2_3);
+                                        const double tmp88 = w36*(C_0_3 + C_0_7);
+                                        const double tmp89 = w40*(-C_1_0 - C_1_4);
+                                        const double tmp90 = w33*(C_0_2 + C_0_6);
+                                        const double tmp91 = w34*(-C_1_2 - C_1_6);
+                                        const double tmp92 = w38*(C_2_1 + C_2_2);
+                                        const double tmp93 = w45*(C_2_5 + C_2_6);
+                                        const double tmp94 = w37*(-C_1_2 - C_1_3 - C_1_6 - C_1_7);
+                                        const double tmp95 = w40*(-C_1_0 - C_1_1 - C_1_4 - C_1_5);
+                                        const double tmp96 = w42*(C_1_0 + C_1_1);
+                                        const double tmp97 = w41*(C_0_0 + C_0_2);
+                                        const double tmp98 = w37*(C_1_2 + C_1_3);
+                                        const double tmp99 = w39*(C_0_1 + C_0_3);
+                                        const double tmp100 = w36*(C_0_4 + C_0_6);
+                                        const double tmp101 = w40*(C_1_4 + C_1_5);
+                                        const double tmp102 = w33*(C_0_5 + C_0_7);
+                                        const double tmp103 = w34*(C_1_6 + C_1_7);
+                                        const double tmp104 = w38*(-C_2_2 - C_2_3);
+                                        const double tmp105 = w35*(-C_2_0 - C_2_1);
+                                        const double tmp106 = w41*(-C_0_3 - C_0_7);
+                                        const double tmp107 = w37*(C_1_2 + C_1_3 + C_1_6 + C_1_7);
+                                        const double tmp108 = w39*(-C_0_2 - C_0_6);
+                                        const double tmp109 = w45*(-C_2_4 - C_2_5);
+                                        const double tmp110 = w36*(-C_0_1 - C_0_5);
+                                        const double tmp111 = w40*(C_1_0 + C_1_1 + C_1_4 + C_1_5);
+                                        const double tmp112 = w33*(-C_0_0 - C_0_4);
+                                        const double tmp113 = w46*(-C_2_6 - C_2_7);
+                                        const double tmp114 = w42*(-C_1_0 - C_1_4);
+                                        const double tmp115 = w41*(-C_0_0 - C_0_4);
+                                        const double tmp116 = w37*(-C_1_2 - C_1_6);
+                                        const double tmp117 = w39*(-C_0_1 - C_0_5);
+                                        const double tmp118 = w36*(-C_0_2 - C_0_6);
+                                        const double tmp119 = w40*(-C_1_1 - C_1_5);
+                                        const double tmp120 = w33*(-C_0_3 - C_0_7);
+                                        const double tmp121 = w34*(-C_1_3 - C_1_7);
+                                        const double tmp122 = w38*(C_2_2 + C_2_3);
+                                        const double tmp123 = w42*(C_1_6 + C_1_7);
+                                        const double tmp124 = w35*(C_2_0 + C_2_1);
+                                        const double tmp125 = w37*(C_1_4 + C_1_5);
+                                        const double tmp126 = w39*(C_0_2 + C_0_4);
+                                        const double tmp127 = w45*(C_2_4 + C_2_5);
+                                        const double tmp128 = w36*(C_0_3 + C_0_5);
+                                        const double tmp129 = w40*(C_1_2 + C_1_3);
+                                        const double tmp130 = w46*(C_2_6 + C_2_7);
+                                        const double tmp131 = w34*(C_1_0 + C_1_1);
+                                        const double tmp132 = w38*(-C_2_1 - C_2_2);
+                                        const double tmp133 = w37*(C_1_2 + C_1_7);
+                                        const double tmp134 = w39*(C_0_1 + C_0_7);
+                                        const double tmp135 = w36*(C_0_0 + C_0_6);
+                                        const double tmp136 = w40*(C_1_0 + C_1_5);
+                                        const double tmp137 = w45*(-C_2_5 - C_2_6);
+                                        const double tmp138 = w38*(-C_2_4 - C_2_6);
+                                        const double tmp139 = w35*(-C_2_5 - C_2_7);
+                                        const double tmp140 = w41*(-C_0_0 - C_0_2);
+                                        const double tmp141 = w37*(-C_1_3 - C_1_6);
+                                        const double tmp142 = w39*(-C_0_1 - C_0_3);
+                                        const double tmp143 = w45*(-C_2_1 - C_2_3);
+                                        const double tmp144 = w36*(-C_0_4 - C_0_6);
+                                        const double tmp145 = w40*(-C_1_1 - C_1_4);
+                                        const double tmp146 = w33*(-C_0_5 - C_0_7);
+                                        const double tmp147 = w46*(-C_2_0 - C_2_2);
+                                        const double tmp148 = w39*(-C_0_3 - C_0_5);
+                                        const double tmp149 = w36*(-C_0_2 - C_0_4);
+                                        const double tmp150 = w38*(C_2_5 + C_2_6);
+                                        const double tmp151 = w37*(-C_1_0 - C_1_5);
+                                        const double tmp152 = w39*(-C_0_0 - C_0_6);
+                                        const double tmp153 = w45*(C_2_1 + C_2_2);
+                                        const double tmp154 = w36*(-C_0_1 - C_0_7);
+                                        const double tmp155 = w40*(-C_1_2 - C_1_7);
+                                        const double tmp156 = w41*(C_0_2 + C_0_6);
+                                        const double tmp157 = w39*(C_0_3 + C_0_7);
+                                        const double tmp158 = w36*(C_0_0 + C_0_4);
+                                        const double tmp159 = w33*(C_0_1 + C_0_5);
+                                        const double tmp160 = w38*(C_2_6 + C_2_7);
+                                        const double tmp161 = w35*(C_2_4 + C_2_5);
+                                        const double tmp162 = w45*(C_2_0 + C_2_1);
+                                        const double tmp163 = w46*(C_2_2 + C_2_3);
+                                        const double tmp164 = w38*(-C_2_0 - C_2_3);
+                                        const double tmp165 = w37*(C_1_3 + C_1_6);
+                                        const double tmp166 = w40*(C_1_1 + C_1_4);
+                                        const double tmp167 = w45*(-C_2_4 - C_2_7);
+                                        const double tmp168 = w39*(C_0_3 + C_0_5);
+                                        const double tmp169 = w36*(C_0_2 + C_0_4);
+                                        const double tmp170 = w38*(C_2_1 + C_2_3);
+                                        const double tmp171 = w35*(C_2_0 + C_2_2);
+                                        const double tmp172 = w41*(C_0_5 + C_0_7);
+                                        const double tmp173 = w37*(C_1_1 + C_1_4);
+                                        const double tmp174 = w39*(C_0_4 + C_0_6);
+                                        const double tmp175 = w45*(C_2_4 + C_2_6);
+                                        const double tmp176 = w36*(C_0_1 + C_0_3);
+                                        const double tmp177 = w40*(C_1_3 + C_1_6);
+                                        const double tmp178 = w33*(C_0_0 + C_0_2);
+                                        const double tmp179 = w46*(C_2_5 + C_2_7);
+                                        const double tmp180 = w38*(-C_2_1 - C_2_3);
+                                        const double tmp181 = w42*(C_1_1 + C_1_5);
+                                        const double tmp182 = w35*(-C_2_0 - C_2_2);
+                                        const double tmp183 = w37*(C_1_3 + C_1_7);
+                                        const double tmp184 = w39*(C_0_1 + C_0_3 + C_0_5 + C_0_7);
+                                        const double tmp185 = w45*(-C_2_4 - C_2_6);
+                                        const double tmp186 = w36*(C_0_0 + C_0_2 + C_0_4 + C_0_6);
+                                        const double tmp187 = w40*(C_1_0 + C_1_4);
+                                        const double tmp188 = w46*(-C_2_5 - C_2_7);
+                                        const double tmp189 = w34*(C_1_2 + C_1_6);
+                                        const double tmp190 = w38*(-C_2_0 - C_2_1);
+                                        const double tmp191 = w35*(-C_2_2 - C_2_3);
+                                        const double tmp192 = w41*(C_0_0 + C_0_4);
+                                        const double tmp193 = w37*(-C_1_0 - C_1_1 - C_1_4 - C_1_5);
+                                        const double tmp194 = w39*(C_0_1 + C_0_5);
+                                        const double tmp195 = w45*(-C_2_6 - C_2_7);
+                                        const double tmp196 = w36*(C_0_2 + C_0_6);
+                                        const double tmp197 = w40*(-C_1_2 - C_1_3 - C_1_6 - C_1_7);
+                                        const double tmp198 = w33*(C_0_3 + C_0_7);
+                                        const double tmp199 = w46*(-C_2_4 - C_2_5);
+                                        const double tmp200 = w38*(-C_2_6 - C_2_7);
+                                        const double tmp201 = w42*(C_1_2 + C_1_3);
+                                        const double tmp202 = w35*(-C_2_4 - C_2_5);
+                                        const double tmp203 = w37*(C_1_0 + C_1_1);
+                                        const double tmp204 = w45*(-C_2_0 - C_2_1);
+                                        const double tmp205 = w40*(C_1_6 + C_1_7);
+                                        const double tmp206 = w46*(-C_2_2 - C_2_3);
+                                        const double tmp207 = w34*(C_1_4 + C_1_5);
+                                        const double tmp208 = w37*(-C_1_1 - C_1_4);
+                                        const double tmp209 = w39*(-C_0_2 - C_0_4);
+                                        const double tmp210 = w36*(-C_0_3 - C_0_5);
+                                        const double tmp211 = w40*(-C_1_3 - C_1_6);
+                                        const double tmp212 = w38*(C_2_4 + C_2_7);
+                                        const double tmp213 = w45*(C_2_0 + C_2_3);
+                                        const double tmp214 = w41*(-C_0_1 - C_0_5);
+                                        const double tmp215 = w39*(-C_0_0 - C_0_4);
+                                        const double tmp216 = w36*(-C_0_3 - C_0_7);
+                                        const double tmp217 = w33*(-C_0_2 - C_0_6);
+                                        const double tmp218 = w42*(-C_1_3 - C_1_7);
+                                        const double tmp219 = w37*(-C_1_1 - C_1_5);
+                                        const double tmp220 = w40*(-C_1_2 - C_1_6);
+                                        const double tmp221 = w34*(-C_1_0 - C_1_4);
+                                        const double tmp222 = w39*(C_0_0 + C_0_6);
+                                        const double tmp223 = w36*(C_0_1 + C_0_7);
+                                        const double tmp224 = w38*(C_2_4 + C_2_5);
+                                        const double tmp225 = w35*(C_2_6 + C_2_7);
+                                        const double tmp226 = w45*(C_2_2 + C_2_3);
+                                        const double tmp227 = w46*(C_2_0 + C_2_1);
+                                        const double tmp228 = w38*(-C_2_0 - C_2_2);
+                                        const double tmp229 = w42*(-C_1_2 - C_1_6);
+                                        const double tmp230 = w35*(-C_2_1 - C_2_3);
+                                        const double tmp231 = w37*(-C_1_0 - C_1_4);
+                                        const double tmp232 = w39*(-C_0_0 - C_0_2 - C_0_4 - C_0_6);
+                                        const double tmp233 = w45*(-C_2_5 - C_2_7);
+                                        const double tmp234 = w36*(-C_0_1 - C_0_3 - C_0_5 - C_0_7);
+                                        const double tmp235 = w40*(-C_1_3 - C_1_7);
+                                        const double tmp236 = w46*(-C_2_4 - C_2_6);
+                                        const double tmp237 = w34*(-C_1_1 - C_1_5);
+                                        const double tmp238 = w42*(C_1_0 + C_1_4);
+                                        const double tmp239 = w37*(C_1_2 + C_1_6);
+                                        const double tmp240 = w40*(C_1_1 + C_1_5);
+                                        const double tmp241 = w34*(C_1_3 + C_1_7);
+                                        const double tmp242 = w38*(-C_2_4 - C_2_5);
+                                        const double tmp243 = w42*(-C_1_0 - C_1_1);
+                                        const double tmp244 = w35*(-C_2_6 - C_2_7);
+                                        const double tmp245 = w37*(-C_1_2 - C_1_3);
+                                        const double tmp246 = w45*(-C_2_2 - C_2_3);
+                                        const double tmp247 = w40*(-C_1_4 - C_1_5);
+                                        const double tmp248 = w46*(-C_2_0 - C_2_1);
+                                        const double tmp249 = w34*(-C_1_6 - C_1_7);
+                                        const double tmp250 = w42*(-C_1_6 - C_1_7);
+                                        const double tmp251 = w37*(-C_1_4 - C_1_5);
+                                        const double tmp252 = w40*(-C_1_2 - C_1_3);
+                                        const double tmp253 = w34*(-C_1_0 - C_1_1);
+                                        const double tmp254 = w38*(C_2_5 + C_2_7);
+                                        const double tmp255 = w35*(C_2_4 + C_2_6);
+                                        const double tmp256 = w45*(C_2_0 + C_2_2);
+                                        const double tmp257 = w46*(C_2_1 + C_2_3);
+                                        const double tmp258 = w38*(-C_2_4 - C_2_5 - C_2_6 - C_2_7);
+                                        const double tmp259 = w45*(-C_2_0 - C_2_1 - C_2_2 - C_2_3);
+                                        const double tmp260 = w38*(C_2_4 + C_2_6);
+                                        const double tmp261 = w35*(C_2_5 + C_2_7);
+                                        const double tmp262 = w45*(C_2_1 + C_2_3);
+                                        const double tmp263 = w46*(C_2_0 + C_2_2);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-C_0_0*w50 - C_0_1*w41 - C_0_6*w33 - C_0_7*w49 + C_1_0*w47 - C_1_2*w42 - C_1_5*w34 + C_1_7*w48 - C_2_0*w43 - C_2_3*w35 - C_2_4*w46 - C_2_7*w44 + tmp132 + tmp137 + tmp208 + tmp209 + tmp210 + tmp211;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=C_0_0*w50 + C_0_1*w41 + C_0_6*w33 + C_0_7*w49 + tmp126 + tmp128 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-C_1_0*w47 + C_1_2*w42 + C_1_5*w34 - C_1_7*w48 + tmp138 + tmp139 + tmp140 + tmp142 + tmp143 + tmp144 + tmp146 + tmp147 + tmp173 + tmp177;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp100 + tmp101 + tmp102 + tmp103 + tmp40 + tmp45 + tmp96 + tmp97 + tmp98 + tmp99;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=C_2_0*w43 + C_2_3*w35 + C_2_4*w46 + C_2_7*w44 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp92 + tmp93;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp192 + tmp193 + tmp194 + tmp196 + tmp197 + tmp198 + tmp224 + tmp225 + tmp226 + tmp227;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp232 + tmp234 + tmp238 + tmp239 + tmp240 + tmp241 + tmp260 + tmp261 + tmp262 + tmp263;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp60 + tmp61 + tmp62 + tmp63 + tmp64 + tmp65;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-C_0_0*w41 - C_0_1*w50 - C_0_6*w49 - C_0_7*w33 + tmp148 + tmp149 + tmp242 + tmp243 + tmp244 + tmp245 + tmp246 + tmp247 + tmp248 + tmp249;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=C_0_0*w41 + C_0_1*w50 + C_0_6*w49 + C_0_7*w33 + C_1_1*w47 - C_1_3*w42 - C_1_4*w34 + C_1_6*w48 - C_2_1*w43 - C_2_2*w35 - C_2_5*w46 - C_2_6*w44 + tmp151 + tmp155 + tmp164 + tmp167 + tmp168 + tmp169;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp101 + tmp103 + tmp40 + tmp42 + tmp44 + tmp45 + tmp46 + tmp48 + tmp96 + tmp98;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-C_1_1*w47 + C_1_3*w42 + C_1_4*w34 - C_1_6*w48 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25 + tmp26 + tmp27 + tmp28 + tmp29;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp193 + tmp197 + tmp214 + tmp215 + tmp216 + tmp217 + tmp224 + tmp225 + tmp226 + tmp227;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=C_2_1*w43 + C_2_2*w35 + C_2_5*w46 + C_2_6*w44 + tmp70 + tmp75 + tmp83 + tmp84 + tmp85 + tmp86 + tmp88 + tmp89 + tmp90 + tmp91;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp60 + tmp61 + tmp63 + tmp65 + tmp80 + tmp81;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp181 + tmp183 + tmp184 + tmp186 + tmp187 + tmp189 + tmp254 + tmp255 + tmp256 + tmp257;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-C_1_0*w42 + C_1_2*w47 + C_1_5*w48 - C_1_7*w34 + tmp138 + tmp139 + tmp140 + tmp141 + tmp142 + tmp143 + tmp144 + tmp145 + tmp146 + tmp147;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp100 + tmp102 + tmp40 + tmp41 + tmp43 + tmp45 + tmp47 + tmp49 + tmp97 + tmp99;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-C_0_2*w50 - C_0_3*w41 - C_0_4*w33 - C_0_5*w49 + C_1_0*w42 - C_1_2*w47 - C_1_5*w48 + C_1_7*w34 - C_2_1*w35 - C_2_2*w43 - C_2_5*w44 - C_2_6*w46 + tmp152 + tmp154 + tmp164 + tmp165 + tmp166 + tmp167;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=C_0_2*w50 + C_0_3*w41 + C_0_4*w33 + C_0_5*w49 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp222 + tmp223;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp229 + tmp231 + tmp232 + tmp234 + tmp235 + tmp237 + tmp260 + tmp261 + tmp262 + tmp263;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp60 + tmp62 + tmp63 + tmp64 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=C_2_1*w35 + C_2_2*w43 + C_2_5*w44 + C_2_6*w46 + tmp70 + tmp71 + tmp72 + tmp73 + tmp74 + tmp75 + tmp76 + tmp77 + tmp78 + tmp79;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp107 + tmp111 + tmp156 + tmp157 + tmp158 + tmp159 + tmp160 + tmp161 + tmp162 + tmp163;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp40 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp48 + tmp49;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-C_1_1*w42 + C_1_3*w47 + C_1_4*w48 - C_1_6*w34 + tmp20 + tmp21 + tmp22 + tmp24 + tmp25 + tmp26 + tmp28 + tmp29 + tmp33 + tmp37;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-C_0_2*w41 - C_0_3*w50 - C_0_4*w49 - C_0_5*w33 + tmp200 + tmp201 + tmp202 + tmp203 + tmp204 + tmp205 + tmp206 + tmp207 + tmp54 + tmp56;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=C_0_2*w41 + C_0_3*w50 + C_0_4*w49 + C_0_5*w33 + C_1_1*w42 - C_1_3*w47 - C_1_4*w48 + C_1_6*w34 - C_2_0*w35 - C_2_3*w43 - C_2_4*w44 - C_2_7*w46 + tmp132 + tmp133 + tmp134 + tmp135 + tmp136 + tmp137;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp60 + tmp63 + tmp80 + tmp81 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp184 + tmp186 + tmp218 + tmp219 + tmp220 + tmp221 + tmp254 + tmp255 + tmp256 + tmp257;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp106 + tmp107 + tmp108 + tmp110 + tmp111 + tmp112 + tmp160 + tmp161 + tmp162 + tmp163;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=C_2_0*w35 + C_2_3*w43 + C_2_4*w44 + C_2_7*w46 + tmp1 + tmp2 + tmp3 + tmp4 + tmp6 + tmp7 + tmp8 + tmp9 + tmp92 + tmp93;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-C_2_0*w46 - C_2_3*w44 - C_2_4*w43 - C_2_7*w35 + tmp0 + tmp114 + tmp115 + tmp116 + tmp117 + tmp118 + tmp119 + tmp120 + tmp121 + tmp5;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp190 + tmp191 + tmp192 + tmp193 + tmp194 + tmp195 + tmp196 + tmp197 + tmp198 + tmp199;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp228 + tmp230 + tmp232 + tmp233 + tmp234 + tmp236 + tmp238 + tmp239 + tmp240 + tmp241;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp62 + tmp64 + tmp65;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-C_0_2*w33 - C_0_3*w49 - C_0_4*w50 - C_0_5*w41 - C_1_1*w34 + C_1_3*w48 + C_1_4*w47 - C_1_6*w42 + C_2_0*w46 + C_2_3*w44 + C_2_4*w43 + C_2_7*w35 + tmp150 + tmp151 + tmp152 + tmp153 + tmp154 + tmp155;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=C_0_2*w33 + C_0_3*w49 + C_0_4*w50 + C_0_5*w41 + tmp222 + tmp223 + tmp50 + tmp51 + tmp52 + tmp53 + tmp55 + tmp57 + tmp58 + tmp59;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=C_1_1*w34 - C_1_3*w48 - C_1_4*w47 + C_1_6*w42 + tmp23 + tmp27 + tmp30 + tmp31 + tmp32 + tmp34 + tmp35 + tmp36 + tmp38 + tmp39;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp18 + tmp19;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp190 + tmp191 + tmp193 + tmp195 + tmp197 + tmp199 + tmp214 + tmp215 + tmp216 + tmp217;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-C_2_1*w46 - C_2_2*w44 - C_2_5*w43 - C_2_6*w35 + tmp82 + tmp83 + tmp84 + tmp85 + tmp86 + tmp87 + tmp88 + tmp89 + tmp90 + tmp91;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp258 + tmp259 + tmp61 + tmp65 + tmp80 + tmp81;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp180 + tmp181 + tmp182 + tmp183 + tmp184 + tmp185 + tmp186 + tmp187 + tmp188 + tmp189;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-C_0_2*w49 - C_0_3*w33 - C_0_4*w41 - C_0_5*w50 + tmp50 + tmp51 + tmp52 + tmp53 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=C_0_2*w49 + C_0_3*w33 + C_0_4*w41 + C_0_5*w50 - C_1_0*w34 + C_1_2*w48 + C_1_5*w47 - C_1_7*w42 + C_2_1*w46 + C_2_2*w44 + C_2_5*w43 + C_2_6*w35 + tmp134 + tmp135 + tmp208 + tmp211 + tmp212 + tmp213;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp10 + tmp11 + tmp13 + tmp15 + tmp17 + tmp19 + tmp66 + tmp67 + tmp68 + tmp69;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=C_1_0*w34 - C_1_2*w48 - C_1_5*w47 + C_1_7*w42 + tmp170 + tmp171 + tmp172 + tmp173 + tmp174 + tmp175 + tmp176 + tmp177 + tmp178 + tmp179;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp228 + tmp229 + tmp230 + tmp231 + tmp232 + tmp233 + tmp234 + tmp235 + tmp236 + tmp237;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp258 + tmp259 + tmp62 + tmp64 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-C_2_1*w44 - C_2_2*w46 - C_2_5*w35 - C_2_6*w43 + tmp71 + tmp72 + tmp73 + tmp74 + tmp76 + tmp77 + tmp78 + tmp79 + tmp82 + tmp87;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp104 + tmp105 + tmp107 + tmp109 + tmp111 + tmp113 + tmp156 + tmp157 + tmp158 + tmp159;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=C_1_1*w48 - C_1_3*w34 - C_1_4*w42 + C_1_6*w47 + tmp30 + tmp31 + tmp32 + tmp33 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp10 + tmp12 + tmp14 + tmp15 + tmp16 + tmp18 + tmp250 + tmp251 + tmp252 + tmp253;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-C_0_0*w33 - C_0_1*w49 - C_0_6*w50 - C_0_7*w41 - C_1_1*w48 + C_1_3*w34 + C_1_4*w42 - C_1_6*w47 + C_2_1*w44 + C_2_2*w46 + C_2_5*w35 + C_2_6*w43 + tmp133 + tmp136 + tmp209 + tmp210 + tmp212 + tmp213;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=C_0_0*w33 + C_0_1*w49 + C_0_6*w50 + C_0_7*w41 + tmp122 + tmp123 + tmp124 + tmp125 + tmp126 + tmp127 + tmp128 + tmp129 + tmp130 + tmp131;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp258 + tmp259 + tmp80 + tmp81 + tmp94 + tmp95;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp180 + tmp182 + tmp184 + tmp185 + tmp186 + tmp188 + tmp218 + tmp219 + tmp220 + tmp221;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp104 + tmp105 + tmp106 + tmp107 + tmp108 + tmp109 + tmp110 + tmp111 + tmp112 + tmp113;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-C_2_0*w44 - C_2_3*w46 - C_2_4*w35 - C_2_7*w43 + tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp10 + tmp15 + tmp250 + tmp251 + tmp252 + tmp253 + tmp66 + tmp67 + tmp68 + tmp69;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=C_1_0*w48 - C_1_2*w34 - C_1_5*w42 + C_1_7*w47 + tmp141 + tmp145 + tmp170 + tmp171 + tmp172 + tmp174 + tmp175 + tmp176 + tmp178 + tmp179;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-C_0_0*w49 - C_0_1*w33 - C_0_6*w41 - C_0_7*w50 + tmp122 + tmp123 + tmp124 + tmp125 + tmp127 + tmp129 + tmp130 + tmp131 + tmp148 + tmp149;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=C_0_0*w49 + C_0_1*w33 + C_0_6*w41 + C_0_7*w50 - C_1_0*w48 + C_1_2*w34 + C_1_5*w42 - C_1_7*w47 + C_2_0*w44 + C_2_3*w46 + C_2_4*w35 + C_2_7*w43 + tmp150 + tmp153 + tmp165 + tmp166 + tmp168 + tmp169;
+                                    }
+                                }
                             } else { // constant data
-                                const double wd0 = 4*d_p[0]*w12;
-                                EM_S[INDEX2(0,0,8)]+=4*wd0;
-                                EM_S[INDEX2(0,1,8)]+=2*wd0;
-                                EM_S[INDEX2(0,2,8)]+=2*wd0;
-                                EM_S[INDEX2(0,3,8)]+=  wd0;
-                                EM_S[INDEX2(1,0,8)]+=2*wd0;
-                                EM_S[INDEX2(1,1,8)]+=4*wd0;
-                                EM_S[INDEX2(1,2,8)]+=  wd0;
-                                EM_S[INDEX2(1,3,8)]+=2*wd0;
-                                EM_S[INDEX2(2,0,8)]+=2*wd0;
-                                EM_S[INDEX2(2,1,8)]+=  wd0;
-                                EM_S[INDEX2(2,2,8)]+=4*wd0;
-                                EM_S[INDEX2(2,3,8)]+=2*wd0;
-                                EM_S[INDEX2(3,0,8)]+=  wd0;
-                                EM_S[INDEX2(3,1,8)]+=2*wd0;
-                                EM_S[INDEX2(3,2,8)]+=2*wd0;
-                                EM_S[INDEX2(3,3,8)]+=4*wd0;
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double wC0 = C_p[INDEX3(k,m,0,numEq,numComp)]*w55;
+                                        const double wC1 = C_p[INDEX3(k,m,1,numEq,numComp)]*w56;
+                                        const double wC2 = C_p[INDEX3(k,m,2,numEq,numComp)]*w54;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+= 4*wC0 + 4*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-4*wC0 + 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+= 2*wC0 - 4*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=-2*wC0 - 2*wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+= 2*wC0 + 2*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=-2*wC0 +   wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=   wC0 - 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=  -wC0 -   wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+= 4*wC0 + 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=-4*wC0 + 4*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+= 2*wC0 - 2*wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=-2*wC0 - 4*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+= 2*wC0 +   wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=-2*wC0 + 2*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=   wC0 -   wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  -wC0 - 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+= 2*wC0 + 4*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=-2*wC0 + 2*wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+= 4*wC0 - 4*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-4*wC0 - 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=   wC0 + 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=  -wC0 +   wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+= 2*wC0 - 2*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=-2*wC0 -   wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+= 2*wC0 + 2*wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=-2*wC0 + 4*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+= 4*wC0 - 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=-4*wC0 - 4*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=   wC0 +   wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  -wC0 + 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+= 2*wC0 -   wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=-2*wC0 - 2*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+= 2*wC0 + 2*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=-2*wC0 +   wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=   wC0 - 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=  -wC0 -   wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+= 4*wC0 + 4*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-4*wC0 + 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+= 2*wC0 - 4*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=-2*wC0 - 2*wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+= 2*wC0 +   wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=-2*wC0 + 2*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=   wC0 -   wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  -wC0 - 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+= 4*wC0 + 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=-4*wC0 + 4*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+= 2*wC0 - 2*wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=-2*wC0 - 4*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=   wC0 + 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=  -wC0 +   wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+= 2*wC0 - 2*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=-2*wC0 -   wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+= 2*wC0 + 4*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=-2*wC0 + 2*wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+= 4*wC0 - 4*wC1 - 4*wC2;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-4*wC0 - 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=   wC0 +   wC1 +   wC2;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  -wC0 + 2*wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+= 2*wC0 -   wC1 + 2*wC2;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=-2*wC0 - 2*wC1 + 4*wC2;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+= 2*wC0 + 2*wC1 -   wC2;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=-2*wC0 + 4*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+= 4*wC0 - 2*wC1 - 2*wC2;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=-4*wC0 - 4*wC1 - 4*wC2;
+                                    }
+                                }
                             }
                         }
                         ///////////////
-                        // process y //
+                        // process D //
                         ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                const double y_0 = y_p[0];
-                                const double y_1 = y_p[1];
-                                const double y_2 = y_p[2];
-                                const double y_3 = y_p[3];
-                                const double tmp0 = 6*w12*(y_1 + y_2);
-                                const double tmp1 = 6*w12*(y_0 + y_3);
-                                EM_F[0]+=tmp0 + 6*w10*y_3 + 6*w11*y_0;
-                                EM_F[1]+=tmp1 + 6*w10*y_2 + 6*w11*y_1;
-                                EM_F[2]+=tmp1 + 6*w10*y_1 + 6*w11*y_2;
-                                EM_F[3]+=tmp0 + 6*w10*y_0 + 6*w11*y_3;
+                        if (!D.isEmpty()) {
+                            const double* D_p=D.getSampleDataRO(e);
+                            if (D.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double D_0 = D_p[INDEX3(k,m,0,numEq,numComp)];
+                                        const double D_1 = D_p[INDEX3(k,m,1,numEq,numComp)];
+                                        const double D_2 = D_p[INDEX3(k,m,2,numEq,numComp)];
+                                        const double D_3 = D_p[INDEX3(k,m,3,numEq,numComp)];
+                                        const double D_4 = D_p[INDEX3(k,m,4,numEq,numComp)];
+                                        const double D_5 = D_p[INDEX3(k,m,5,numEq,numComp)];
+                                        const double D_6 = D_p[INDEX3(k,m,6,numEq,numComp)];
+                                        const double D_7 = D_p[INDEX3(k,m,7,numEq,numComp)];
+                                        const double tmp0 = w59*(D_3 + D_7);
+                                        const double tmp1 = w57*(D_0 + D_4);
+                                        const double tmp2 = w58*(D_1 + D_2 + D_5 + D_6);
+                                        const double tmp3 = w60*(D_0 + D_1 + D_2 + D_3);
+                                        const double tmp4 = w61*(D_4 + D_5 + D_6 + D_7);
+                                        const double tmp5 = w59*(D_1 + D_3);
+                                        const double tmp6 = w57*(D_4 + D_6);
+                                        const double tmp7 = w58*(D_0 + D_2 + D_5 + D_7);
+                                        const double tmp8 = w59*(D_4 + D_6);
+                                        const double tmp9 = w57*(D_1 + D_3);
+                                        const double tmp10 = w60*(D_4 + D_5 + D_6 + D_7);
+                                        const double tmp11 = w61*(D_0 + D_1 + D_2 + D_3);
+                                        const double tmp12 = w59*(D_4 + D_5);
+                                        const double tmp13 = w57*(D_2 + D_3);
+                                        const double tmp14 = w58*(D_0 + D_1 + D_6 + D_7);
+                                        const double tmp15 = w58*(D_0 + D_1 + D_2 + D_3 + D_4 + D_5 + D_6 + D_7);
+                                        const double tmp16 = w59*(D_2 + D_6);
+                                        const double tmp17 = w57*(D_1 + D_5);
+                                        const double tmp18 = w58*(D_0 + D_3 + D_4 + D_7);
+                                        const double tmp19 = w59*(D_1 + D_5);
+                                        const double tmp20 = w57*(D_2 + D_6);
+                                        const double tmp21 = w60*(D_0 + D_1 + D_4 + D_5);
+                                        const double tmp22 = w61*(D_2 + D_3 + D_6 + D_7);
+                                        const double tmp23 = w59*(D_0 + D_4);
+                                        const double tmp24 = w57*(D_3 + D_7);
+                                        const double tmp25 = w59*(D_6 + D_7);
+                                        const double tmp26 = w57*(D_0 + D_1);
+                                        const double tmp27 = w58*(D_2 + D_3 + D_4 + D_5);
+                                        const double tmp28 = w60*(D_0 + D_5 + D_6);
+                                        const double tmp29 = w61*(D_1 + D_2 + D_7);
+                                        const double tmp30 = w59*(D_0 + D_2);
+                                        const double tmp31 = w57*(D_5 + D_7);
+                                        const double tmp32 = w58*(D_1 + D_3 + D_4 + D_6);
+                                        const double tmp33 = w60*(D_1 + D_2 + D_7);
+                                        const double tmp34 = w61*(D_0 + D_5 + D_6);
+                                        const double tmp35 = w60*(D_1 + D_4 + D_7);
+                                        const double tmp36 = w61*(D_0 + D_3 + D_6);
+                                        const double tmp37 = w60*(D_1 + D_2 + D_4);
+                                        const double tmp38 = w61*(D_3 + D_5 + D_6);
+                                        const double tmp39 = w59*(D_5 + D_7);
+                                        const double tmp40 = w57*(D_0 + D_2);
+                                        const double tmp41 = w60*(D_0 + D_2 + D_4 + D_6);
+                                        const double tmp42 = w61*(D_1 + D_3 + D_5 + D_7);
+                                        const double tmp43 = w60*(D_2 + D_3 + D_6 + D_7);
+                                        const double tmp44 = w61*(D_0 + D_1 + D_4 + D_5);
+                                        const double tmp45 = w60*(D_2 + D_4 + D_7);
+                                        const double tmp46 = w61*(D_0 + D_3 + D_5);
+                                        const double tmp47 = w59*(D_2 + D_3);
+                                        const double tmp48 = w57*(D_4 + D_5);
+                                        const double tmp49 = w60*(D_3 + D_5 + D_6);
+                                        const double tmp50 = w61*(D_1 + D_2 + D_4);
+                                        const double tmp51 = w60*(D_0 + D_3 + D_5);
+                                        const double tmp52 = w61*(D_2 + D_4 + D_7);
+                                        const double tmp53 = w60*(D_0 + D_3 + D_6);
+                                        const double tmp54 = w61*(D_1 + D_4 + D_7);
+                                        const double tmp55 = w60*(D_1 + D_3 + D_5 + D_7);
+                                        const double tmp56 = w61*(D_0 + D_2 + D_4 + D_6);
+                                        const double tmp57 = w59*(D_0 + D_1);
+                                        const double tmp58 = w57*(D_6 + D_7);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=D_0*w62 + D_7*w63 + tmp49 + tmp50;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp27 + tmp57 + tmp58;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp30 + tmp31 + tmp32;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp10 + tmp11;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp2 + tmp23 + tmp24;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp43 + tmp44;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp55 + tmp56;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp27 + tmp57 + tmp58;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=D_1*w62 + D_6*w63 + tmp45 + tmp46;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp10 + tmp11;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp5 + tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp43 + tmp44;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp18 + tmp19 + tmp20;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp41 + tmp42;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp30 + tmp31 + tmp32;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp10 + tmp11;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=D_2*w62 + D_5*w63 + tmp35 + tmp36;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp14 + tmp47 + tmp48;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp55 + tmp56;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp16 + tmp17 + tmp18;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp21 + tmp22;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp10 + tmp11;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp5 + tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp14 + tmp47 + tmp48;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=D_3*w62 + D_4*w63 + tmp28 + tmp29;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp41 + tmp42;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp21 + tmp22;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0 + tmp1 + tmp2;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp2 + tmp23 + tmp24;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp43 + tmp44;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp55 + tmp56;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=D_3*w63 + D_4*w62 + tmp33 + tmp34;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp12 + tmp13 + tmp14;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp7 + tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp43 + tmp44;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp18 + tmp19 + tmp20;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp41 + tmp42;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp12 + tmp13 + tmp14;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=D_2*w63 + D_5*w62 + tmp53 + tmp54;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp32 + tmp39 + tmp40;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp55 + tmp56;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp16 + tmp17 + tmp18;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp21 + tmp22;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp7 + tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=D_1*w63 + D_6*w62 + tmp51 + tmp52;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp25 + tmp26 + tmp27;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=tmp15;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp41 + tmp42;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp21 + tmp22;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1 + tmp2;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp32 + tmp39 + tmp40;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp25 + tmp26 + tmp27;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=D_0*w63 + D_7*w62 + tmp37 + tmp38;
+                                    }
+                                 }
                             } else { // constant data
-                                EM_F[0]+=36*w12*y_p[0];
-                                EM_F[1]+=36*w12*y_p[0];
-                                EM_F[2]+=36*w12*y_p[0];
-                                EM_F[3]+=36*w12*y_p[0];
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double wD0 = 8*D_p[INDEX2(k, m, numEq)]*w58;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=8*wD0;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=  wD0;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=2*wD0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=4*wD0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=8*wD0;
+                                    }
+                                }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // k0 loop
-                } // k1 loop
-            } // colouring
-        } // face 4
-
-        if (domain->m_faceOffset[5] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
                         ///////////////
-                        // process d //
+                        // process X //
                         ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                const double d_0 = d_p[0];
-                                const double d_1 = d_p[1];
-                                const double d_2 = d_p[2];
-                                const double d_3 = d_p[3];
-                                const double tmp0 = w12*(d_0 + d_1 + d_2 + d_3);
-                                const double tmp1 = w10*(d_1 + d_3);
-                                const double tmp2 = w11*(d_0 + d_2);
-                                const double tmp3 = w10*(d_2 + d_3);
-                                const double tmp4 = w11*(d_0 + d_1);
-                                const double tmp5 = w10*(d_0 + d_1);
-                                const double tmp6 = w11*(d_2 + d_3);
-                                const double tmp7 = w12*(d_1 + d_2);
-                                const double tmp8 = w10*(d_0 + d_2);
-                                const double tmp9 = w11*(d_1 + d_3);
-                                const double tmp10 = w12*(d_0 + d_3);
-                                EM_S[INDEX2(4,4,8)]+=d_0*w14 + d_3*w13 + tmp7;
-                                EM_S[INDEX2(4,5,8)]+=tmp3 + tmp4;
-                                EM_S[INDEX2(4,6,8)]+=tmp1 + tmp2;
-                                EM_S[INDEX2(4,7,8)]+=tmp0;
-                                EM_S[INDEX2(5,4,8)]+=tmp3 + tmp4;
-                                EM_S[INDEX2(5,5,8)]+=d_1*w14 + d_2*w13 + tmp10;
-                                EM_S[INDEX2(5,6,8)]+=tmp0;
-                                EM_S[INDEX2(5,7,8)]+=tmp8 + tmp9;
-                                EM_S[INDEX2(6,4,8)]+=tmp1 + tmp2;
-                                EM_S[INDEX2(6,5,8)]+=tmp0;
-                                EM_S[INDEX2(6,6,8)]+=d_1*w13 + d_2*w14 + tmp10;
-                                EM_S[INDEX2(6,7,8)]+=tmp5 + tmp6;
-                                EM_S[INDEX2(7,4,8)]+=tmp0;
-                                EM_S[INDEX2(7,5,8)]+=tmp8 + tmp9;
-                                EM_S[INDEX2(7,6,8)]+=tmp5 + tmp6;
-                                EM_S[INDEX2(7,7,8)]+=d_0*w13 + d_3*w14 + tmp7;
+                        if (!X.isEmpty()) {
+                            const double* X_p=X.getSampleDataRO(e);
+                            if (X.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double X_0_0 = X_p[INDEX3(k,0,0,numEq,3)];
+                                    const double X_1_0 = X_p[INDEX3(k,1,0,numEq,3)];
+                                    const double X_2_0 = X_p[INDEX3(k,2,0,numEq,3)];
+                                    const double X_0_1 = X_p[INDEX3(k,0,1,numEq,3)];
+                                    const double X_1_1 = X_p[INDEX3(k,1,1,numEq,3)];
+                                    const double X_2_1 = X_p[INDEX3(k,2,1,numEq,3)];
+                                    const double X_0_2 = X_p[INDEX3(k,0,2,numEq,3)];
+                                    const double X_1_2 = X_p[INDEX3(k,1,2,numEq,3)];
+                                    const double X_2_2 = X_p[INDEX3(k,2,2,numEq,3)];
+                                    const double X_0_3 = X_p[INDEX3(k,0,3,numEq,3)];
+                                    const double X_1_3 = X_p[INDEX3(k,1,3,numEq,3)];
+                                    const double X_2_3 = X_p[INDEX3(k,2,3,numEq,3)];
+                                    const double X_0_4 = X_p[INDEX3(k,0,4,numEq,3)];
+                                    const double X_1_4 = X_p[INDEX3(k,1,4,numEq,3)];
+                                    const double X_2_4 = X_p[INDEX3(k,2,4,numEq,3)];
+                                    const double X_0_5 = X_p[INDEX3(k,0,5,numEq,3)];
+                                    const double X_1_5 = X_p[INDEX3(k,1,5,numEq,3)];
+                                    const double X_2_5 = X_p[INDEX3(k,2,5,numEq,3)];
+                                    const double X_0_6 = X_p[INDEX3(k,0,6,numEq,3)];
+                                    const double X_1_6 = X_p[INDEX3(k,1,6,numEq,3)];
+                                    const double X_2_6 = X_p[INDEX3(k,2,6,numEq,3)];
+                                    const double X_0_7 = X_p[INDEX3(k,0,7,numEq,3)];
+                                    const double X_1_7 = X_p[INDEX3(k,1,7,numEq,3)];
+                                    const double X_2_7 = X_p[INDEX3(k,2,7,numEq,3)];
+                                    const double tmp0 = w72*(X_0_6 + X_0_7);
+                                    const double tmp1 = w66*(X_2_0 + X_2_4);
+                                    const double tmp2 = w64*(X_0_0 + X_0_1);
+                                    const double tmp3 = w68*(X_2_1 + X_2_2 + X_2_5 + X_2_6);
+                                    const double tmp4 = w65*(X_1_0 + X_1_2);
+                                    const double tmp5 = w70*(X_2_3 + X_2_7);
+                                    const double tmp6 = w67*(X_1_1 + X_1_3 + X_1_4 + X_1_6);
+                                    const double tmp7 = w71*(X_1_5 + X_1_7);
+                                    const double tmp8 = w69*(X_0_2 + X_0_3 + X_0_4 + X_0_5);
+                                    const double tmp9 = w72*(-X_0_6 - X_0_7);
+                                    const double tmp10 = w66*(X_2_1 + X_2_5);
+                                    const double tmp11 = w64*(-X_0_0 - X_0_1);
+                                    const double tmp12 = w68*(X_2_0 + X_2_3 + X_2_4 + X_2_7);
+                                    const double tmp13 = w65*(X_1_1 + X_1_3);
+                                    const double tmp14 = w70*(X_2_2 + X_2_6);
+                                    const double tmp15 = w67*(X_1_0 + X_1_2 + X_1_5 + X_1_7);
+                                    const double tmp16 = w71*(X_1_4 + X_1_6);
+                                    const double tmp17 = w69*(-X_0_2 - X_0_3 - X_0_4 - X_0_5);
+                                    const double tmp18 = w72*(X_0_4 + X_0_5);
+                                    const double tmp19 = w66*(X_2_2 + X_2_6);
+                                    const double tmp20 = w64*(X_0_2 + X_0_3);
+                                    const double tmp21 = w65*(-X_1_0 - X_1_2);
+                                    const double tmp22 = w70*(X_2_1 + X_2_5);
+                                    const double tmp23 = w67*(-X_1_1 - X_1_3 - X_1_4 - X_1_6);
+                                    const double tmp24 = w71*(-X_1_5 - X_1_7);
+                                    const double tmp25 = w69*(X_0_0 + X_0_1 + X_0_6 + X_0_7);
+                                    const double tmp26 = w72*(-X_0_4 - X_0_5);
+                                    const double tmp27 = w66*(X_2_3 + X_2_7);
+                                    const double tmp28 = w64*(-X_0_2 - X_0_3);
+                                    const double tmp29 = w65*(-X_1_1 - X_1_3);
+                                    const double tmp30 = w70*(X_2_0 + X_2_4);
+                                    const double tmp31 = w67*(-X_1_0 - X_1_2 - X_1_5 - X_1_7);
+                                    const double tmp32 = w71*(-X_1_4 - X_1_6);
+                                    const double tmp33 = w69*(-X_0_0 - X_0_1 - X_0_6 - X_0_7);
+                                    const double tmp34 = w72*(X_0_2 + X_0_3);
+                                    const double tmp35 = w66*(-X_2_0 - X_2_4);
+                                    const double tmp36 = w64*(X_0_4 + X_0_5);
+                                    const double tmp37 = w68*(-X_2_1 - X_2_2 - X_2_5 - X_2_6);
+                                    const double tmp38 = w65*(X_1_4 + X_1_6);
+                                    const double tmp39 = w70*(-X_2_3 - X_2_7);
+                                    const double tmp40 = w71*(X_1_1 + X_1_3);
+                                    const double tmp41 = w72*(-X_0_2 - X_0_3);
+                                    const double tmp42 = w66*(-X_2_1 - X_2_5);
+                                    const double tmp43 = w64*(-X_0_4 - X_0_5);
+                                    const double tmp44 = w68*(-X_2_0 - X_2_3 - X_2_4 - X_2_7);
+                                    const double tmp45 = w65*(X_1_5 + X_1_7);
+                                    const double tmp46 = w70*(-X_2_2 - X_2_6);
+                                    const double tmp47 = w71*(X_1_0 + X_1_2);
+                                    const double tmp48 = w72*(X_0_0 + X_0_1);
+                                    const double tmp49 = w66*(-X_2_2 - X_2_6);
+                                    const double tmp50 = w64*(X_0_6 + X_0_7);
+                                    const double tmp51 = w65*(-X_1_4 - X_1_6);
+                                    const double tmp52 = w70*(-X_2_1 - X_2_5);
+                                    const double tmp53 = w71*(-X_1_1 - X_1_3);
+                                    const double tmp54 = w72*(-X_0_0 - X_0_1);
+                                    const double tmp55 = w66*(-X_2_3 - X_2_7);
+                                    const double tmp56 = w64*(-X_0_6 - X_0_7);
+                                    const double tmp57 = w65*(-X_1_5 - X_1_7);
+                                    const double tmp58 = w70*(-X_2_0 - X_2_4);
+                                    const double tmp59 = w71*(-X_1_0 - X_1_2);
+                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 + tmp7 + tmp8;
+                                    EM_F[INDEX2(k,1,numEq)]+=tmp10 + tmp11 + tmp12 + tmp13 + tmp14 + tmp15 + tmp16 + tmp17 + tmp9;
+                                    EM_F[INDEX2(k,2,numEq)]+=tmp12 + tmp18 + tmp19 + tmp20 + tmp21 + tmp22 + tmp23 + tmp24 + tmp25;
+                                    EM_F[INDEX2(k,3,numEq)]+=tmp26 + tmp27 + tmp28 + tmp29 + tmp3 + tmp30 + tmp31 + tmp32 + tmp33;
+                                    EM_F[INDEX2(k,4,numEq)]+=tmp15 + tmp25 + tmp34 + tmp35 + tmp36 + tmp37 + tmp38 + tmp39 + tmp40;
+                                    EM_F[INDEX2(k,5,numEq)]+=tmp33 + tmp41 + tmp42 + tmp43 + tmp44 + tmp45 + tmp46 + tmp47 + tmp6;
+                                    EM_F[INDEX2(k,6,numEq)]+=tmp31 + tmp44 + tmp48 + tmp49 + tmp50 + tmp51 + tmp52 + tmp53 + tmp8;
+                                    EM_F[INDEX2(k,7,numEq)]+=tmp17 + tmp23 + tmp37 + tmp54 + tmp55 + tmp56 + tmp57 + tmp58 + tmp59;
+                                }
                             } else { // constant data
-                                const double wd0 = 4*d_p[0]*w12;
-                                EM_S[INDEX2(4,4,8)]+=4*wd0;
-                                EM_S[INDEX2(4,5,8)]+=2*wd0;
-                                EM_S[INDEX2(4,6,8)]+=2*wd0;
-                                EM_S[INDEX2(4,7,8)]+=  wd0;
-                                EM_S[INDEX2(5,4,8)]+=2*wd0;
-                                EM_S[INDEX2(5,5,8)]+=4*wd0;
-                                EM_S[INDEX2(5,6,8)]+=  wd0;
-                                EM_S[INDEX2(5,7,8)]+=2*wd0;
-                                EM_S[INDEX2(6,4,8)]+=2*wd0;
-                                EM_S[INDEX2(6,5,8)]+=  wd0;
-                                EM_S[INDEX2(6,6,8)]+=4*wd0;
-                                EM_S[INDEX2(6,7,8)]+=2*wd0;
-                                EM_S[INDEX2(7,4,8)]+=  wd0;
-                                EM_S[INDEX2(7,5,8)]+=2*wd0;
-                                EM_S[INDEX2(7,6,8)]+=2*wd0;
-                                EM_S[INDEX2(7,7,8)]+=4*wd0;
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double wX0 = 18*X_p[INDEX2(k, 0, numEq)]*w55;
+                                    const double wX1 = 18*X_p[INDEX2(k, 1, numEq)]*w56;
+                                    const double wX2 = 18*X_p[INDEX2(k, 2, numEq)]*w54;
+                                    EM_F[INDEX2(k,0,numEq)]+= wX0 + wX1 + wX2;
+                                    EM_F[INDEX2(k,1,numEq)]+=-wX0 + wX1 + wX2;
+                                    EM_F[INDEX2(k,2,numEq)]+= wX0 - wX1 + wX2;
+                                    EM_F[INDEX2(k,3,numEq)]+=-wX0 - wX1 + wX2;
+                                    EM_F[INDEX2(k,4,numEq)]+= wX0 + wX1 - wX2;
+                                    EM_F[INDEX2(k,5,numEq)]+=-wX0 + wX1 - wX2;
+                                    EM_F[INDEX2(k,6,numEq)]+= wX0 - wX1 - wX2;
+                                    EM_F[INDEX2(k,7,numEq)]+=-wX0 - wX1 - wX2;
+                                }
                             }
                         }
                         ///////////////
-                        // process y //
+                        // process Y //
                         ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                const double y_0 = y_p[0];
-                                const double y_1 = y_p[1];
-                                const double y_2 = y_p[2];
-                                const double y_3 = y_p[3];
-                                const double tmp0 = 6*w12*(y_1 + y_2);
-                                const double tmp1 = 6*w12*(y_0 + y_3);
-                                EM_F[4]+=tmp0 + 6*w10*y_3 + 6*w11*y_0;
-                                EM_F[5]+=tmp1 + 6*w10*y_2 + 6*w11*y_1;
-                                EM_F[6]+=tmp1 + 6*w10*y_1 + 6*w11*y_2;
-                                EM_F[7]+=tmp0 + 6*w10*y_0 + 6*w11*y_3;
+                        if (!Y.isEmpty()) {
+                            const double* Y_p=Y.getSampleDataRO(e);
+                            if (Y.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double Y_0 = Y_p[INDEX2(k, 0, numEq)];
+                                    const double Y_1 = Y_p[INDEX2(k, 1, numEq)];
+                                    const double Y_2 = Y_p[INDEX2(k, 2, numEq)];
+                                    const double Y_3 = Y_p[INDEX2(k, 3, numEq)];
+                                    const double Y_4 = Y_p[INDEX2(k, 4, numEq)];
+                                    const double Y_5 = Y_p[INDEX2(k, 5, numEq)];
+                                    const double Y_6 = Y_p[INDEX2(k, 6, numEq)];
+                                    const double Y_7 = Y_p[INDEX2(k, 7, numEq)];
+                                    const double tmp0 = w76*(Y_3 + Y_5 + Y_6);
+                                    const double tmp1 = w75*(Y_1 + Y_2 + Y_4);
+                                    const double tmp2 = w76*(Y_2 + Y_4 + Y_7);
+                                    const double tmp3 = w75*(Y_0 + Y_3 + Y_5);
+                                    const double tmp4 = w76*(Y_1 + Y_4 + Y_7);
+                                    const double tmp5 = w75*(Y_0 + Y_3 + Y_6);
+                                    const double tmp6 = w76*(Y_0 + Y_5 + Y_6);
+                                    const double tmp7 = w75*(Y_1 + Y_2 + Y_7);
+                                    const double tmp8 = w76*(Y_1 + Y_2 + Y_7);
+                                    const double tmp9 = w75*(Y_0 + Y_5 + Y_6);
+                                    const double tmp10 = w76*(Y_0 + Y_3 + Y_6);
+                                    const double tmp11 = w75*(Y_1 + Y_4 + Y_7);
+                                    const double tmp12 = w76*(Y_0 + Y_3 + Y_5);
+                                    const double tmp13 = w75*(Y_2 + Y_4 + Y_7);
+                                    const double tmp14 = w76*(Y_1 + Y_2 + Y_4);
+                                    const double tmp15 = w75*(Y_3 + Y_5 + Y_6);
+                                    EM_F[INDEX2(k,0,numEq)]+=Y_0*w74 + Y_7*w77 + tmp0 + tmp1;
+                                    EM_F[INDEX2(k,1,numEq)]+=Y_1*w74 + Y_6*w77 + tmp2 + tmp3;
+                                    EM_F[INDEX2(k,2,numEq)]+=Y_2*w74 + Y_5*w77 + tmp4 + tmp5;
+                                    EM_F[INDEX2(k,3,numEq)]+=Y_3*w74 + Y_4*w77 + tmp6 + tmp7;
+                                    EM_F[INDEX2(k,4,numEq)]+=Y_3*w77 + Y_4*w74 + tmp8 + tmp9;
+                                    EM_F[INDEX2(k,5,numEq)]+=Y_2*w77 + Y_5*w74 + tmp10 + tmp11;
+                                    EM_F[INDEX2(k,6,numEq)]+=Y_1*w77 + Y_6*w74 + tmp12 + tmp13;
+                                    EM_F[INDEX2(k,7,numEq)]+=Y_0*w77 + Y_7*w74 + tmp14 + tmp15;
+                                }
                             } else { // constant data
-                                EM_F[4]+=36*w12*y_p[0];
-                                EM_F[5]+=36*w12*y_p[0];
-                                EM_F[6]+=36*w12*y_p[0];
-                                EM_F[7]+=36*w12*y_p[0];
+                                for (index_t k=0; k<numEq; k++) {
+                                    EM_F[INDEX2(k,0,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,1,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,2,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,3,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,4,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,5,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,6,numEq)]+=216*Y_p[k]*w58;
+                                    EM_F[INDEX2(k,7,numEq)]+=216*Y_p[k]*w58;
+                                }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // k0 loop
-                } // k1 loop
-            } // colouring
-        } // face 5
+
+                        // add to matrix (if add_EM_S) and RHS (if add_EM_F)
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
+                    } // end k0 loop
+                } // end k1 loop
+            } // end k2 loop
+        } // end of colouring
     } // end of parallel region
 }
 
-//protected
-void DefaultAssembler3D::assemblePDEBoundarySingleReduced(
-                                        AbstractSystemMatrix* mat, Data& rhs,
-                                        const Data& d, const Data& y) const
+/****************************************************************************/
+// PDE SYSTEM BOUNDARY
+/****************************************************************************/
+
+void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
+                               Data& rhs, const Data& d, const Data& y) const
 {
-    const double w0 = m_dx[0]*m_dx[1]/16;
-    const double w1 = m_dx[0]*m_dx[2]/16;
-    const double w2 = m_dx[1]*m_dx[2]/16;
-    const bool add_EM_S=!d.isEmpty();
-    const bool add_EM_F=!y.isEmpty();
+    dim_t numEq, numComp;
+    if (!mat)
+        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
+    else {
+        numEq=mat->getRowBlockSize();
+        numComp=mat->getColumnBlockSize();
+    }
+    const double SQRT3 = 1.73205080756887719318;
+    const double w12 = m_dx[0]*m_dx[1]/144;
+    const double w10 = w12*(-SQRT3 + 2);
+    const double w11 = w12*(SQRT3 + 2);
+    const double w13 = w12*(-4*SQRT3 + 7);
+    const double w14 = w12*(4*SQRT3 + 7);
+    const double w7 = m_dx[0]*m_dx[2]/144;
+    const double w5 = w7*(-SQRT3 + 2);
+    const double w6 = w7*(SQRT3 + 2);
+    const double w8 = w7*(-4*SQRT3 + 7);
+    const double w9 = w7*(4*SQRT3 + 7);
+    const double w2 = m_dx[1]*m_dx[2]/144;
+    const double w0 = w2*(-SQRT3 + 2);
+    const double w1 = w2*(SQRT3 + 2);
+    const double w3 = w2*(-4*SQRT3 + 7);
+    const double w4 = w2*(4*SQRT3 + 7);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
+    const bool add_EM_S = !d.isEmpty();
+    const bool add_EM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8*numEq*numComp, 0);
+        vector<double> EM_F(8*numEq, 0);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = INDEX2(k1,k2,NE1);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            EM_S[INDEX2(0,0,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(2,0,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(4,0,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(6,0,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(0,2,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(2,2,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(4,2,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(6,2,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(0,4,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(2,4,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(4,4,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(6,4,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(0,6,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(2,6,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(4,6,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(6,6,8)]+=d_p[0]*w2;
+                            if (d.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
+                                        const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
+                                        const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
+                                        const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
+                                        const double tmp0 = w0*(d_0 + d_1);
+                                        const double tmp1 = w1*(d_2 + d_3);
+                                        const double tmp2 = w0*(d_0 + d_2);
+                                        const double tmp3 = w1*(d_1 + d_3);
+                                        const double tmp4 = w0*(d_1 + d_3);
+                                        const double tmp5 = w1*(d_0 + d_2);
+                                        const double tmp6 = w0*(d_2 + d_3);
+                                        const double tmp7 = w1*(d_0 + d_1);
+                                        const double tmp8 = w2*(d_0 + d_3);
+                                        const double tmp9 = w2*(d_1 + d_2);
+                                        const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = d_0*w4 + d_3*w3 + tmp9;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = d_1*w4 + d_2*w3 + tmp8;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = d_1*w3 + d_2*w4 + tmp8;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = d_0*w3 + d_3*w4 + tmp9;
+                                    }
+                                 }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w2;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = 4*wd0;
+                                    }
+                                }
+                            }
                         }
                         ///////////////
                         // process y //
                         ///////////////
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
-                            EM_F[0]+=4*w2*y_p[0];
-                            EM_F[2]+=4*w2*y_p[0];
-                            EM_F[4]+=4*w2*y_p[0];
-                            EM_F[6]+=4*w2*y_p[0];
+                            if (y.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
+                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
+                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
+                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
+                                    const double tmp0 = 6*w2*(y_1 + y_2);
+                                    const double tmp1 = 6*w2*(y_0 + y_3);
+                                    EM_F[INDEX2(k,0,numEq)] = tmp0 + 6*w0*y_3 + 6*w1*y_0;
+                                    EM_F[INDEX2(k,2,numEq)] = tmp1 + 6*w0*y_2 + 6*w1*y_1;
+                                    EM_F[INDEX2(k,4,numEq)] = tmp1 + 6*w0*y_1 + 6*w1*y_2;
+                                    EM_F[INDEX2(k,6,numEq)] = tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                                }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    EM_F[INDEX2(k,0,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,2,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,4,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,6,numEq)] = 36*w2*y_p[k];
+                                }
+                            }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 0
 
         if (domain->m_faceOffset[1] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
                         const index_t e = domain->m_faceOffset[1]+INDEX2(k1,k2,NE1);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            EM_S[INDEX2(1,1,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(3,1,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(5,1,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(7,1,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(1,3,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(3,3,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(5,3,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(7,3,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(1,5,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(3,5,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(5,5,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(7,5,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(1,7,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(3,7,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(5,7,8)]+=d_p[0]*w2;
-                            EM_S[INDEX2(7,7,8)]+=d_p[0]*w2;
+                            if (d.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
+                                        const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
+                                        const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
+                                        const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
+                                        const double tmp0 = w0*(d_0 + d_2);
+                                        const double tmp1 = w1*(d_1 + d_3);
+                                        const double tmp2 = w0*(d_2 + d_3);
+                                        const double tmp3 = w1*(d_0 + d_1);
+                                        const double tmp4 = w0*(d_1 + d_3);
+                                        const double tmp5 = w1*(d_0 + d_2);
+                                        const double tmp6 = w2*(d_0 + d_3);
+                                        const double tmp7 = w2*(d_1 + d_2);
+                                        const double tmp8 = w0*(d_0 + d_1);
+                                        const double tmp9 = w1*(d_2 + d_3);
+                                        const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = d_0*w4 + d_3*w3 + tmp7;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = d_1*w4 + d_2*w3 + tmp6;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = d_1*w3 + d_2*w4 + tmp6;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = d_0*w3 + d_3*w4 + tmp7;
+                                    }
+                                 }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w2;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = 4*wd0;
+                                    }
+                                }
+                            }
                         }
                         ///////////////
                         // process y //
                         ///////////////
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
-                            EM_F[1]+=4*w2*y_p[0];
-                            EM_F[3]+=4*w2*y_p[0];
-                            EM_F[5]+=4*w2*y_p[0];
-                            EM_F[7]+=4*w2*y_p[0];
+                            if (y.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
+                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
+                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
+                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
+                                    const double tmp0 = 6*w2*(y_1 + y_2);
+                                    const double tmp1 = 6*w2*(y_0 + y_3);
+                                    EM_F[INDEX2(k,1,numEq)] = tmp0 + 6*w0*y_3 + 6*w1*y_0;
+                                    EM_F[INDEX2(k,3,numEq)] = tmp1 + 6*w0*y_2 + 6*w1*y_1;
+                                    EM_F[INDEX2(k,5,numEq)] = tmp1 + 6*w0*y_1 + 6*w1*y_2;
+                                    EM_F[INDEX2(k,7,numEq)] = tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                                }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    EM_F[INDEX2(k,1,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,3,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,5,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,7,numEq)] = 36*w2*y_p[k];
+                                }
+                            }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(k1+1)-2;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 1
 
         if (domain->m_faceOffset[2] > -1) {
-            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
-#pragma omp for
-                for (index_t k2=k2_0; k2<NE2; k2+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,NE0);
-                        ///////////////
-                        // process d //
-                        ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            EM_S[INDEX2(0,0,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(1,0,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(4,0,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(5,0,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(0,1,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(1,1,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(4,1,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(5,1,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(0,4,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(1,4,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(4,4,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(5,4,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(0,5,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(1,5,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(4,5,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(5,5,8)]+=d_p[0]*w1;
-                        }
-                        ///////////////
-                        // process y //
-                        ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            EM_F[0]+=4*w1*y_p[0];
-                            EM_F[1]+=4*w1*y_p[0];
-                            EM_F[4]+=4*w1*y_p[0];
-                            EM_F[5]+=4*w1*y_p[0];
-                        }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // k0 loop
-                } // k2 loop
-            } // colouring
-        } // face 2
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
 
-        if (domain->m_faceOffset[3] > -1) {
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,NE0);
-                        ///////////////
-                        // process d //
-                        ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            EM_S[INDEX2(2,2,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(3,2,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(6,2,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(7,2,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(2,3,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(3,3,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(6,3,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(7,3,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(2,6,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(3,6,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(6,6,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(7,6,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(2,7,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(3,7,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(6,7,8)]+=d_p[0]*w1;
-                            EM_S[INDEX2(7,7,8)]+=d_p[0]*w1;
-                        }
-                        ///////////////
-                        // process y //
-                        ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            EM_F[2]+=4*w1*y_p[0];
-                            EM_F[3]+=4*w1*y_p[0];
-                            EM_F[6]+=4*w1*y_p[0];
-                            EM_F[7]+=4*w1*y_p[0];
-                        }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // k0 loop
-                } // k2 loop
-            } // colouring
-        } // face 3
-
-        if (domain->m_faceOffset[4] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
-                        ///////////////
-                        // process d //
-                        ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            EM_S[INDEX2(0,0,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(1,0,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(2,0,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(3,0,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(0,1,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(1,1,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(2,1,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(3,1,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(0,2,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(1,2,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(2,2,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(3,2,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(0,3,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(1,3,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(2,3,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(3,3,8)]+=d_p[0]*w0;
-                        }
-                        ///////////////
-                        // process y //
-                        ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            EM_F[0]+=4*w0*y_p[0];
-                            EM_F[1]+=4*w0*y_p[0];
-                            EM_F[2]+=4*w0*y_p[0];
-                            EM_F[3]+=4*w0*y_p[0];
-                        }
-                        const index_t firstNode=m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
-                    } // k0 loop
-                } // k1 loop
-            } // colouring
-        } // face 4
-
-        if (domain->m_faceOffset[5] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8, 0);
-                        vector<double> EM_F(8, 0);
-                        const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
+                        const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,NE0);
                         ///////////////
                         // process d //
                         ///////////////
                         if (add_EM_S) {
                             const double* d_p=d.getSampleDataRO(e);
-                            EM_S[INDEX2(4,4,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(5,4,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(6,4,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(7,4,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(4,5,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(5,5,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(6,5,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(7,5,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(4,6,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(5,6,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(6,6,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(7,6,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(4,7,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(5,7,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(6,7,8)]+=d_p[0]*w0;
-                            EM_S[INDEX2(7,7,8)]+=d_p[0]*w0;
+                            if (d.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
+                                        const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
+                                        const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
+                                        const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
+                                        const double tmp0 = w5*(d_0 + d_1);
+                                        const double tmp1 = w6*(d_2 + d_3);
+                                        const double tmp2 = w5*(d_0 + d_2);
+                                        const double tmp3 = w6*(d_1 + d_3);
+                                        const double tmp4 = w5*(d_1 + d_3);
+                                        const double tmp5 = w6*(d_0 + d_2);
+                                        const double tmp6 = w7*(d_0 + d_3);
+                                        const double tmp7 = w7*(d_0 + d_1 + d_2 + d_3);
+                                        const double tmp8 = w7*(d_1 + d_2);
+                                        const double tmp9 = w5*(d_2 + d_3);
+                                        const double tmp10 = w6*(d_0 + d_1);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = d_0*w9 + d_3*w8 + tmp8;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = d_1*w9 + d_2*w8 + tmp6;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = d_1*w8 + d_2*w9 + tmp6;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = d_0*w8 + d_3*w9 + tmp8;
+                                    }
+                                 }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    for (index_t m=0; m<numComp; m++) {
+                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w7;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = 4*wd0;
+                                    }
+                                }
+                            }
                         }
                         ///////////////
                         // process y //
                         ///////////////
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
-                            EM_F[4]+=4*w0*y_p[0];
-                            EM_F[5]+=4*w0*y_p[0];
-                            EM_F[6]+=4*w0*y_p[0];
-                            EM_F[7]+=4*w0*y_p[0];
+                            if (y.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
+                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
+                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
+                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
+                                    const double tmp0 = 6*w7*(y_1 + y_2);
+                                    const double tmp1 = 6*w7*(y_0 + y_3);
+                                    EM_F[INDEX2(k,0,numEq)] = tmp0 + 6*w5*y_3 + 6*w6*y_0;
+                                    EM_F[INDEX2(k,1,numEq)] = tmp1 + 6*w5*y_2 + 6*w6*y_1;
+                                    EM_F[INDEX2(k,4,numEq)] = tmp1 + 6*w5*y_1 + 6*w6*y_2;
+                                    EM_F[INDEX2(k,5,numEq)] = tmp0 + 6*w5*y_0 + 6*w6*y_3;
+                                }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    EM_F[INDEX2(k,0,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,1,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,4,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,5,numEq)] = 36*w7*y_p[k];
+                                }
+                            }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode);
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
-                } // k1 loop
+                } // k2 loop
             } // colouring
-        } // face 5
-    } // end of parallel region
-}
+        } // face 2
 
-//protected
-void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
-                               Data& rhs, const Data& d, const Data& y) const
-{
-    dim_t numEq, numComp;
-    if (!mat)
-        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
-    else {
-        numEq=mat->getRowBlockSize();
-        numComp=mat->getColumnBlockSize();
-    }
-    const double SQRT3 = 1.73205080756887719318;
-    const double w12 = m_dx[0]*m_dx[1]/144;
-    const double w10 = w12*(-SQRT3 + 2);
-    const double w11 = w12*(SQRT3 + 2);
-    const double w13 = w12*(-4*SQRT3 + 7);
-    const double w14 = w12*(4*SQRT3 + 7);
-    const double w7 = m_dx[0]*m_dx[2]/144;
-    const double w5 = w7*(-SQRT3 + 2);
-    const double w6 = w7*(SQRT3 + 2);
-    const double w8 = w7*(-4*SQRT3 + 7);
-    const double w9 = w7*(4*SQRT3 + 7);
-    const double w2 = m_dx[1]*m_dx[2]/144;
-    const double w0 = w2*(-SQRT3 + 2);
-    const double w1 = w2*(SQRT3 + 2);
-    const double w3 = w2*(-4*SQRT3 + 7);
-    const double w4 = w2*(4*SQRT3 + 7);
-    const bool add_EM_S=!d.isEmpty();
-    const bool add_EM_F=!y.isEmpty();
-    const int NE0 = m_NE[0];
-    const int NE1 = m_NE[1];
-    const int NE2 = m_NE[2];
-    rhs.requireWrite();
+        if (domain->m_faceOffset[3] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
 
-#pragma omp parallel
-    {
-        if (domain->m_faceOffset[0] > -1) {
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
-                    for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = INDEX2(k1,k2,NE1);
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,NE0);
                         ///////////////
                         // process d //
                         ///////////////
@@ -6069,55 +6117,55 @@ void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                         const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
                                         const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double tmp0 = w0*(d_0 + d_1);
-                                        const double tmp1 = w1*(d_2 + d_3);
-                                        const double tmp2 = w0*(d_0 + d_2);
-                                        const double tmp3 = w1*(d_1 + d_3);
-                                        const double tmp4 = w0*(d_1 + d_3);
-                                        const double tmp5 = w1*(d_0 + d_2);
-                                        const double tmp6 = w0*(d_2 + d_3);
-                                        const double tmp7 = w1*(d_0 + d_1);
-                                        const double tmp8 = w2*(d_0 + d_3);
-                                        const double tmp9 = w2*(d_1 + d_2);
-                                        const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=d_0*w4 + d_3*w3 + tmp9;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=d_1*w4 + d_2*w3 + tmp8;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=d_1*w3 + d_2*w4 + tmp8;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=d_0*w3 + d_3*w4 + tmp9;
+                                        const double tmp0 = w5*(d_0 + d_2);
+                                        const double tmp1 = w6*(d_1 + d_3);
+                                        const double tmp2 = w5*(d_1 + d_3);
+                                        const double tmp3 = w6*(d_0 + d_2);
+                                        const double tmp4 = w7*(d_0 + d_1 + d_2 + d_3);
+                                        const double tmp5 = w5*(d_0 + d_1);
+                                        const double tmp6 = w6*(d_2 + d_3);
+                                        const double tmp7 = w7*(d_0 + d_3);
+                                        const double tmp8 = w7*(d_1 + d_2);
+                                        const double tmp9 = w5*(d_2 + d_3);
+                                        const double tmp10 = w6*(d_0 + d_1);
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = d_0*w9 + d_3*w8 + tmp8;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = d_1*w9 + d_2*w8 + tmp7;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = d_1*w8 + d_2*w9 + tmp7;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = d_0*w8 + d_3*w9 + tmp8;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
-                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w2;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=4*wd0;
+                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w7;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -6133,38 +6181,41 @@ void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_1 = y_p[INDEX2(k, 1, numEq)];
                                     const double y_2 = y_p[INDEX2(k, 2, numEq)];
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
-                                    const double tmp0 = 6*w2*(y_1 + y_2);
-                                    const double tmp1 = 6*w2*(y_0 + y_3);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + 6*w0*y_3 + 6*w1*y_0;
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp1 + 6*w0*y_2 + 6*w1*y_1;
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp1 + 6*w0*y_1 + 6*w1*y_2;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                                    const double tmp0 = 6*w7*(y_1 + y_2);
+                                    const double tmp1 = 6*w7*(y_0 + y_3);
+                                    EM_F[INDEX2(k,2,numEq)] = tmp0 + 6*w5*y_3 + 6*w6*y_0;
+                                    EM_F[INDEX2(k,3,numEq)] = tmp1 + 6*w5*y_2 + 6*w6*y_1;
+                                    EM_F[INDEX2(k,6,numEq)] = tmp1 + 6*w5*y_1 + 6*w6*y_2;
+                                    EM_F[INDEX2(k,7,numEq)] = tmp0 + 6*w5*y_0 + 6*w6*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,2,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,4,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,6,numEq)]+=36*w2*y_p[k];
+                                    EM_F[INDEX2(k,2,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,3,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,6,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,7,numEq)] = 36*w7*y_p[k];
                                 }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // k1 loop
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
+                    } // k0 loop
                 } // k2 loop
             } // colouring
-        } // face 0
+        } // face 3
 
-        if (domain->m_faceOffset[1] > -1) {
-            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+        if (domain->m_faceOffset[4] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
-                for (index_t k2=k2_0; k2<NE2; k2+=2) {
-                    for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = domain->m_faceOffset[1]+INDEX2(k1,k2,NE1);
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
+                    for (index_t k0=0; k0<NE0; ++k0) {
+                        const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
                         ///////////////
                         // process d //
                         ///////////////
@@ -6177,55 +6228,55 @@ void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                         const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
                                         const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double tmp0 = w0*(d_0 + d_2);
-                                        const double tmp1 = w1*(d_1 + d_3);
-                                        const double tmp2 = w0*(d_2 + d_3);
-                                        const double tmp3 = w1*(d_0 + d_1);
-                                        const double tmp4 = w0*(d_1 + d_3);
-                                        const double tmp5 = w1*(d_0 + d_2);
-                                        const double tmp6 = w2*(d_0 + d_3);
-                                        const double tmp7 = w2*(d_1 + d_2);
-                                        const double tmp8 = w0*(d_0 + d_1);
-                                        const double tmp9 = w1*(d_2 + d_3);
-                                        const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=d_0*w4 + d_3*w3 + tmp7;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=d_1*w4 + d_2*w3 + tmp6;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=d_1*w3 + d_2*w4 + tmp6;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=d_0*w3 + d_3*w4 + tmp7;
+                                        const double tmp0 = w10*(d_0 + d_2);
+                                        const double tmp1 = w11*(d_1 + d_3);
+                                        const double tmp2 = w12*(d_0 + d_1 + d_2 + d_3);
+                                        const double tmp3 = w12*(d_1 + d_2);
+                                        const double tmp4 = w10*(d_1 + d_3);
+                                        const double tmp5 = w11*(d_0 + d_2);
+                                        const double tmp6 = w12*(d_0 + d_3);
+                                        const double tmp7 = w10*(d_0 + d_1);
+                                        const double tmp8 = w11*(d_2 + d_3);
+                                        const double tmp9 = w10*(d_2 + d_3);
+                                        const double tmp10 = w11*(d_0 + d_1);
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = d_0*w14 + d_3*w13 + tmp3;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = d_1*w14 + d_2*w13 + tmp6;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = d_1*w13 + d_2*w14 + tmp6;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = tmp7 + tmp8;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = tmp7 + tmp8;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = d_0*w13 + d_3*w14 + tmp3;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
-                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w2;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=4*wd0;
+                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w12;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -6241,38 +6292,41 @@ void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_1 = y_p[INDEX2(k, 1, numEq)];
                                     const double y_2 = y_p[INDEX2(k, 2, numEq)];
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
-                                    const double tmp0 = 6*w2*(y_1 + y_2);
-                                    const double tmp1 = 6*w2*(y_0 + y_3);
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp0 + 6*w0*y_3 + 6*w1*y_0;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp1 + 6*w0*y_2 + 6*w1*y_1;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp1 + 6*w0*y_1 + 6*w1*y_2;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                                    const double tmp0 = 6*w12*(y_1 + y_2);
+                                    const double tmp1 = 6*w12*(y_0 + y_3);
+                                    EM_F[INDEX2(k,0,numEq)] = tmp0 + 6*w10*y_3 + 6*w11*y_0;
+                                    EM_F[INDEX2(k,1,numEq)] = tmp1 + 6*w10*y_2 + 6*w11*y_1;
+                                    EM_F[INDEX2(k,2,numEq)] = tmp1 + 6*w10*y_1 + 6*w11*y_2;
+                                    EM_F[INDEX2(k,3,numEq)] = tmp0 + 6*w10*y_0 + 6*w11*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,1,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,3,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,5,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,7,numEq)]+=36*w2*y_p[k];
+                                    EM_F[INDEX2(k,0,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,1,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,2,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,3,numEq)] = 36*w12*y_p[k];
                                 }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(k1+1)-2;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // k1 loop
-                } // k2 loop
+                        const index_t firstNode=m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
+                    } // k0 loop
+                } // k1 loop
             } // colouring
-        } // face 1
+        } // face 4
 
-        if (domain->m_faceOffset[2] > -1) {
-            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+        if (domain->m_faceOffset[5] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
+            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
-                for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                for (index_t k1=k1_0; k1<NE1; k1+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,NE0);
+                        const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
                         ///////////////
                         // process d //
                         ///////////////
@@ -6285,421 +6339,509 @@ void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                         const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
                                         const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double tmp0 = w5*(d_0 + d_1);
-                                        const double tmp1 = w6*(d_2 + d_3);
-                                        const double tmp2 = w5*(d_0 + d_2);
-                                        const double tmp3 = w6*(d_1 + d_3);
-                                        const double tmp4 = w5*(d_1 + d_3);
-                                        const double tmp5 = w6*(d_0 + d_2);
-                                        const double tmp6 = w7*(d_0 + d_3);
-                                        const double tmp7 = w7*(d_0 + d_1 + d_2 + d_3);
-                                        const double tmp8 = w7*(d_1 + d_2);
-                                        const double tmp9 = w5*(d_2 + d_3);
-                                        const double tmp10 = w6*(d_0 + d_1);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=d_0*w9 + d_3*w8 + tmp8;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=d_1*w9 + d_2*w8 + tmp6;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=d_1*w8 + d_2*w9 + tmp6;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=d_0*w8 + d_3*w9 + tmp8;
+                                        const double tmp0 = w12*(d_0 + d_1 + d_2 + d_3);
+                                        const double tmp1 = w10*(d_1 + d_3);
+                                        const double tmp2 = w11*(d_0 + d_2);
+                                        const double tmp3 = w10*(d_2 + d_3);
+                                        const double tmp4 = w11*(d_0 + d_1);
+                                        const double tmp5 = w10*(d_0 + d_1);
+                                        const double tmp6 = w11*(d_2 + d_3);
+                                        const double tmp7 = w12*(d_1 + d_2);
+                                        const double tmp8 = w10*(d_0 + d_2);
+                                        const double tmp9 = w11*(d_1 + d_3);
+                                        const double tmp10 = w12*(d_0 + d_3);
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = d_0*w14 + d_3*w13 + tmp7;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = tmp1 + tmp2;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = d_1*w14 + d_2*w13 + tmp10;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = tmp1 + tmp2;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = d_1*w13 + d_2*w14 + tmp10;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = d_0*w13 + d_3*w14 + tmp7;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
-                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w7;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=4*wd0;
+                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w12;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
                         }
                         ///////////////
-                        // process y //
+                        // process y //
+                        ///////////////
+                        if (add_EM_F) {
+                            const double* y_p=y.getSampleDataRO(e);
+                            if (y.actsExpanded()) {
+                                for (index_t k=0; k<numEq; k++) {
+                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
+                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
+                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
+                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
+                                    const double tmp0 = 6*w12*(y_1 + y_2);
+                                    const double tmp1 = 6*w12*(y_0 + y_3);
+                                    EM_F[INDEX2(k,4,numEq)] = tmp0 + 6*w10*y_3 + 6*w11*y_0;
+                                    EM_F[INDEX2(k,5,numEq)] = tmp1 + 6*w10*y_2 + 6*w11*y_1;
+                                    EM_F[INDEX2(k,6,numEq)] = tmp1 + 6*w10*y_1 + 6*w11*y_2;
+                                    EM_F[INDEX2(k,7,numEq)] = tmp0 + 6*w10*y_0 + 6*w11*y_3;
+                                }
+                            } else { // constant data
+                                for (index_t k=0; k<numEq; k++) {
+                                    EM_F[INDEX2(k,4,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,5,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,6,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,7,numEq)] = 36*w12*y_p[k];
+                                }
+                            }
+                        }
+                        const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
+                    } // k0 loop
+                } // k1 loop
+            } // colouring
+        } // face 5
+    } // end of parallel region
+}
+
+/****************************************************************************/
+// PDE SYSTEM REDUCED
+/****************************************************************************/
+
+void DefaultAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+                                     Data& rhs, const Data& A, const Data& B,
+                                     const Data& C, const Data& D,
+                                     const Data& X, const Data& Y) const
+{
+    dim_t numEq, numComp;
+    if (!mat)
+        numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
+    else {
+        numEq=mat->getRowBlockSize();
+        numComp=mat->getColumnBlockSize();
+    }
+
+    const double w0 = m_dx[0]/16;
+    const double w1 = m_dx[1]/16;
+    const double w2 = m_dx[2]/16;
+    const double w3 = m_dx[0]*m_dx[1]/32;
+    const double w4 = m_dx[0]*m_dx[2]/32;
+    const double w5 = m_dx[1]*m_dx[2]/32;
+    const double w6 = m_dx[0]*m_dx[1]/(16*m_dx[2]);
+    const double w7 = m_dx[0]*m_dx[2]/(16*m_dx[1]);
+    const double w8 = m_dx[1]*m_dx[2]/(16*m_dx[0]);
+    const double w9 = m_dx[0]*m_dx[1]*m_dx[2]/64;
+    const int NE0 = m_NE[0];
+    const int NE1 = m_NE[1];
+    const int NE2 = m_NE[2];
+    const bool add_EM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool add_EM_F = (!X.isEmpty() || !Y.isEmpty());
+    rhs.requireWrite();
+
+#pragma omp parallel
+    {
+        vector<double> EM_S(8*8*numEq*numComp, 0);
+        vector<double> EM_F(8*numEq, 0);
+
+        for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
+#pragma omp for
+            for (index_t k2=k2_0; k2<NE2; k2+=2) {
+                for (index_t k1=0; k1<NE1; ++k1) {
+                    for (index_t k0=0; k0<NE0; ++k0)  {
+                        const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                        if (add_EM_S)
+                            fill(EM_S.begin(), EM_S.end(), 0);
+                        if (add_EM_F)
+                            fill(EM_F.begin(), EM_F.end(), 0);
+
+                        ///////////////
+                        // process A //
+                        ///////////////
+                        if (!A.isEmpty()) {
+                            const double* A_p=A.getSampleDataRO(e);
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double Aw00 = A_p[INDEX4(k,0,m,0,numEq,3,numComp)]*w8;
+                                    const double Aw10 = A_p[INDEX4(k,1,m,0,numEq,3,numComp)]*w2;
+                                    const double Aw20 = A_p[INDEX4(k,2,m,0,numEq,3,numComp)]*w1;
+                                    const double Aw01 = A_p[INDEX4(k,0,m,1,numEq,3,numComp)]*w2;
+                                    const double Aw11 = A_p[INDEX4(k,1,m,1,numEq,3,numComp)]*w7;
+                                    const double Aw21 = A_p[INDEX4(k,2,m,1,numEq,3,numComp)]*w0;
+                                    const double Aw02 = A_p[INDEX4(k,0,m,2,numEq,3,numComp)]*w1;
+                                    const double Aw12 = A_p[INDEX4(k,1,m,2,numEq,3,numComp)]*w0;
+                                    const double Aw22 = A_p[INDEX4(k,2,m,2,numEq,3,numComp)]*w6;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 + Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 + Aw10 + Aw11 - Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+= Aw00 + Aw01 - Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=-Aw00 - Aw01 + Aw02 - Aw10 - Aw11 + Aw12 - Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 - Aw20 + Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 - Aw10 + Aw11 - Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=-Aw00 + Aw01 - Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+= Aw00 - Aw01 + Aw02 + Aw10 - Aw11 + Aw12 + Aw20 - Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 + Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 + Aw10 - Aw11 - Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+= Aw00 - Aw01 - Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-Aw00 + Aw01 + Aw02 - Aw10 + Aw11 + Aw12 - Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 - Aw20 - Aw21 - Aw22;
+                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 - Aw10 - Aw11 - Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-Aw00 - Aw01 - Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+= Aw00 + Aw01 + Aw02 + Aw10 + Aw11 + Aw12 + Aw20 + Aw21 + Aw22;
+                                }
+                            }
+                        }
+                        ///////////////
+                        // process B //
                         ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
-                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
-                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
-                                    const double tmp0 = 6*w7*(y_1 + y_2);
-                                    const double tmp1 = 6*w7*(y_0 + y_3);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + 6*w5*y_3 + 6*w6*y_0;
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp1 + 6*w5*y_2 + 6*w6*y_1;
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp1 + 6*w5*y_1 + 6*w6*y_2;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp0 + 6*w5*y_0 + 6*w6*y_3;
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,1,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,4,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,5,numEq)]+=36*w7*y_p[k];
+                        if (!B.isEmpty()) {
+                            const double* B_p=B.getSampleDataRO(e);
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double wB0 = B_p[INDEX3(k,0,m, numEq, 3)]*w5;
+                                    const double wB1 = B_p[INDEX3(k,1,m, numEq, 3)]*w4;
+                                    const double wB2 = B_p[INDEX3(k,2,m, numEq, 3)]*w3;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=-wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+= wB0 - wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=-wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+= wB0 + wB1 - wB2;
+                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=-wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+= wB0 - wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=-wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+= wB0 + wB1 + wB2;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+= wB0 + wB1 + wB2;
                                 }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // k0 loop
-                } // k2 loop
-            } // colouring
-        } // face 2
-
-        if (domain->m_faceOffset[3] > -1) {
-            for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
-#pragma omp for
-                for (index_t k2=k2_0; k2<NE2; k2+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,NE0);
                         ///////////////
-                        // process d //
+                        // process C //
                         ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
-                                        const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
-                                        const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
-                                        const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double tmp0 = w5*(d_0 + d_2);
-                                        const double tmp1 = w6*(d_1 + d_3);
-                                        const double tmp2 = w5*(d_1 + d_3);
-                                        const double tmp3 = w6*(d_0 + d_2);
-                                        const double tmp4 = w7*(d_0 + d_1 + d_2 + d_3);
-                                        const double tmp5 = w5*(d_0 + d_1);
-                                        const double tmp6 = w6*(d_2 + d_3);
-                                        const double tmp7 = w7*(d_0 + d_3);
-                                        const double tmp8 = w7*(d_1 + d_2);
-                                        const double tmp9 = w5*(d_2 + d_3);
-                                        const double tmp10 = w6*(d_0 + d_1);
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=d_0*w9 + d_3*w8 + tmp8;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=d_1*w9 + d_2*w8 + tmp7;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=d_1*w8 + d_2*w9 + tmp7;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=d_0*w8 + d_3*w9 + tmp8;
-                                    }
-                                 }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w7;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=4*wd0;
-                                    }
+                        if (!C.isEmpty()) {
+                            const double* C_p=C.getSampleDataRO(e);
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double wC0 = C_p[INDEX3(k, m, 0, numEq, numComp)]*w5;
+                                    const double wC1 = C_p[INDEX3(k, m, 1, numEq, numComp)]*w4;
+                                    const double wC2 = C_p[INDEX3(k, m, 2, numEq, numComp)]*w3;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=-wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+= wC0 - wC1 - wC2;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=-wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+= wC0 + wC1 - wC2;
+                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=-wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+= wC0 - wC1 + wC2;
+                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=-wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+= wC0 + wC1 + wC2;
                                 }
                             }
                         }
                         ///////////////
-                        // process y //
+                        // process D //
                         ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
-                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
-                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
-                                    const double tmp0 = 6*w7*(y_1 + y_2);
-                                    const double tmp1 = 6*w7*(y_0 + y_3);
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp0 + 6*w5*y_3 + 6*w6*y_0;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp1 + 6*w5*y_2 + 6*w6*y_1;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp1 + 6*w5*y_1 + 6*w6*y_2;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp0 + 6*w5*y_0 + 6*w6*y_3;
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,2,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,3,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,6,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,7,numEq)]+=36*w7*y_p[k];
+                        if (!D.isEmpty()) {
+                            const double* D_p=D.getSampleDataRO(e);
+                            for (index_t k=0; k<numEq; k++) {
+                                for (index_t m=0; m<numComp; m++) {
+                                    const double wD = D_p[INDEX2(k, m, numEq)]*w9;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,0,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,0,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=wD;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=wD;
                                 }
                             }
                         }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // k0 loop
-                } // k2 loop
-            } // colouring
-        } // face 3
-
-        if (domain->m_faceOffset[4] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
                         ///////////////
-                        // process d //
+                        // process X //
                         ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
-                                        const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
-                                        const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
-                                        const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double tmp0 = w10*(d_0 + d_2);
-                                        const double tmp1 = w11*(d_1 + d_3);
-                                        const double tmp2 = w12*(d_0 + d_1 + d_2 + d_3);
-                                        const double tmp3 = w12*(d_1 + d_2);
-                                        const double tmp4 = w10*(d_1 + d_3);
-                                        const double tmp5 = w11*(d_0 + d_2);
-                                        const double tmp6 = w12*(d_0 + d_3);
-                                        const double tmp7 = w10*(d_0 + d_1);
-                                        const double tmp8 = w11*(d_2 + d_3);
-                                        const double tmp9 = w10*(d_2 + d_3);
-                                        const double tmp10 = w11*(d_0 + d_1);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=d_0*w14 + d_3*w13 + tmp3;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=d_1*w14 + d_2*w13 + tmp6;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=d_1*w13 + d_2*w14 + tmp6;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp7 + tmp8;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp7 + tmp8;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=d_0*w13 + d_3*w14 + tmp3;
-                                    }
-                                 }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w12;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=4*wd0;
-                                    }
-                                }
+                        if (!X.isEmpty()) {
+                            const double* X_p=X.getSampleDataRO(e);
+                            for (index_t k=0; k<numEq; k++) {
+                                const double wX0 = 8*X_p[INDEX2(k, 0, numEq)]*w5;
+                                const double wX1 = 8*X_p[INDEX2(k, 1, numEq)]*w4;
+                                const double wX2 = 8*X_p[INDEX2(k, 2, numEq)]*w3;
+                                EM_F[INDEX2(k,0,numEq)]+=-wX0 - wX1 - wX2;
+                                EM_F[INDEX2(k,1,numEq)]+= wX0 - wX1 - wX2;
+                                EM_F[INDEX2(k,2,numEq)]+=-wX0 + wX1 - wX2;
+                                EM_F[INDEX2(k,3,numEq)]+= wX0 + wX1 - wX2;
+                                EM_F[INDEX2(k,4,numEq)]+=-wX0 - wX1 + wX2;
+                                EM_F[INDEX2(k,5,numEq)]+= wX0 - wX1 + wX2;
+                                EM_F[INDEX2(k,6,numEq)]+=-wX0 + wX1 + wX2;
+                                EM_F[INDEX2(k,7,numEq)]+= wX0 + wX1 + wX2;
                             }
                         }
                         ///////////////
-                        // process y //
+                        // process Y //
                         ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
-                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
-                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
-                                    const double tmp0 = 6*w12*(y_1 + y_2);
-                                    const double tmp1 = 6*w12*(y_0 + y_3);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + 6*w10*y_3 + 6*w11*y_0;
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp1 + 6*w10*y_2 + 6*w11*y_1;
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp1 + 6*w10*y_1 + 6*w11*y_2;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp0 + 6*w10*y_0 + 6*w11*y_3;
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,1,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,2,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,3,numEq)]+=36*w12*y_p[k];
-                                }
+                        if (!Y.isEmpty()) {
+                            const double* Y_p=Y.getSampleDataRO(e);
+                            for (index_t k=0; k<numEq; k++) {
+                                EM_F[INDEX2(k,0,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,1,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,2,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,3,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,4,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,5,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,6,numEq)]+=8*Y_p[k]*w9;
+                                EM_F[INDEX2(k,7,numEq)]+=8*Y_p[k]*w9;
                             }
                         }
-                        const index_t firstNode=m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // k0 loop
-                } // k1 loop
-            } // colouring
-        } // face 4
 
-        if (domain->m_faceOffset[5] > -1) {
-            for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
-#pragma omp for
-                for (index_t k1=k1_0; k1<NE1; k1+=2) {
-                    for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
-                        const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
-                        ///////////////
-                        // process d //
-                        ///////////////
-                        if (add_EM_S) {
-                            const double* d_p=d.getSampleDataRO(e);
-                            if (d.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
-                                        const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
-                                        const double d_2 = d_p[INDEX3(k,m,2,numEq,numComp)];
-                                        const double d_3 = d_p[INDEX3(k,m,3,numEq,numComp)];
-                                        const double tmp0 = w12*(d_0 + d_1 + d_2 + d_3);
-                                        const double tmp1 = w10*(d_1 + d_3);
-                                        const double tmp2 = w11*(d_0 + d_2);
-                                        const double tmp3 = w10*(d_2 + d_3);
-                                        const double tmp4 = w11*(d_0 + d_1);
-                                        const double tmp5 = w10*(d_0 + d_1);
-                                        const double tmp6 = w11*(d_2 + d_3);
-                                        const double tmp7 = w12*(d_1 + d_2);
-                                        const double tmp8 = w10*(d_0 + d_2);
-                                        const double tmp9 = w11*(d_1 + d_3);
-                                        const double tmp10 = w12*(d_0 + d_3);
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=d_0*w14 + d_3*w13 + tmp7;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp1 + tmp2;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=d_1*w14 + d_2*w13 + tmp10;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp1 + tmp2;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=d_1*w13 + d_2*w14 + tmp10;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=d_0*w13 + d_3*w14 + tmp7;
-                                    }
-                                 }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    for (index_t m=0; m<numComp; m++) {
-                                        const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w12;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=4*wd0;
-                                    }
-                                }
-                            }
-                        }
-                        ///////////////
-                        // process y //
-                        ///////////////
-                        if (add_EM_F) {
-                            const double* y_p=y.getSampleDataRO(e);
-                            if (y.actsExpanded()) {
-                                for (index_t k=0; k<numEq; k++) {
-                                    const double y_0 = y_p[INDEX2(k, 0, numEq)];
-                                    const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                    const double y_2 = y_p[INDEX2(k, 2, numEq)];
-                                    const double y_3 = y_p[INDEX2(k, 3, numEq)];
-                                    const double tmp0 = 6*w12*(y_1 + y_2);
-                                    const double tmp1 = 6*w12*(y_0 + y_3);
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp0 + 6*w10*y_3 + 6*w11*y_0;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp1 + 6*w10*y_2 + 6*w11*y_1;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp1 + 6*w10*y_1 + 6*w11*y_2;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp0 + 6*w10*y_0 + 6*w11*y_3;
-                                }
-                            } else { // constant data
-                                for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,4,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,5,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,6,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,7,numEq)]+=36*w12*y_p[k];
-                                }
-                            }
-                        }
-                        const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
-                    } // k0 loop
-                } // k1 loop
-            } // colouring
-        } // face 5
+                        // add to matrix (if add_EM_S) and RHS (if add_EM_F)
+                        const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1+k0;
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
+                    } // end k0 loop
+                } // end k1 loop
+            } // end k2 loop
+        } // end of colouring
     } // end of parallel region
 }
 
-//protected
+/****************************************************************************/
+// PDE SYSTEM REDUCED BOUNDARY
+/****************************************************************************/
+
 void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                                         AbstractSystemMatrix* mat, Data& rhs,
                                         const Data& d, const Data& y) const
@@ -6714,22 +6856,28 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
     const double w0 = m_dx[0]*m_dx[1]/16.;
     const double w1 = m_dx[0]*m_dx[2]/16.;
     const double w2 = m_dx[1]*m_dx[2]/16.;
-    const bool add_EM_S=!d.isEmpty();
-    const bool add_EM_F=!y.isEmpty();
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
+    const bool add_EM_S = !d.isEmpty();
+    const bool add_EM_F = !y.isEmpty();
     rhs.requireWrite();
 
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8*numEq*numComp, 0);
+        vector<double> EM_F(8*numEq, 0);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = INDEX2(k1,k2,NE1);
                         ///////////////
                         // process d //
@@ -6739,22 +6887,22 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double tmp0 = d_p[INDEX2(k, m, numEq)]*w2;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=tmp0;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]=tmp0;
                                 }
                             }
                         }
@@ -6764,27 +6912,30 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=4*w2*y_p[k];
-                                EM_F[INDEX2(k,2,numEq)]+=4*w2*y_p[k];
-                                EM_F[INDEX2(k,4,numEq)]+=4*w2*y_p[k];
-                                EM_F[INDEX2(k,6,numEq)]+=4*w2*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 4*w2*y_p[k];
+                                EM_F[INDEX2(k,2,numEq)] = 4*w2*y_p[k];
+                                EM_F[INDEX2(k,4,numEq)] = 4*w2*y_p[k];
+                                EM_F[INDEX2(k,6,numEq)] = 4*w2*y_p[k];
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 0
 
         if (domain->m_faceOffset[1] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k1=0; k1<NE1; ++k1) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[1]+INDEX2(k1,k2,NE1);
                         ///////////////
                         // process d //
@@ -6794,22 +6945,22 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double tmp0 = d_p[INDEX2(k, m, numEq)]*w2;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=tmp0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]=tmp0;
                                 }
                             }
                         }
@@ -6819,27 +6970,30 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,1,numEq)]+=4*w2*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=4*w2*y_p[k];
-                                EM_F[INDEX2(k,5,numEq)]+=4*w2*y_p[k];
-                                EM_F[INDEX2(k,7,numEq)]+=4*w2*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 4*w2*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 4*w2*y_p[k];
+                                EM_F[INDEX2(k,5,numEq)] = 4*w2*y_p[k];
+                                EM_F[INDEX2(k,7,numEq)] = 4*w2*y_p[k];
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(k1+1)-2;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 1
 
         if (domain->m_faceOffset[2] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,NE0);
                         ///////////////
                         // process d //
@@ -6849,22 +7003,22 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double tmp0 = d_p[INDEX2(k, m, numEq)]*w1;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=tmp0;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]=tmp0;
                                 }
                             }
                         }
@@ -6874,27 +7028,30 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=4*w1*y_p[k];
-                                EM_F[INDEX2(k,1,numEq)]+=4*w1*y_p[k];
-                                EM_F[INDEX2(k,4,numEq)]+=4*w1*y_p[k];
-                                EM_F[INDEX2(k,5,numEq)]+=4*w1*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 4*w1*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 4*w1*y_p[k];
+                                EM_F[INDEX2(k,4,numEq)] = 4*w1*y_p[k];
+                                EM_F[INDEX2(k,5,numEq)] = 4*w1*y_p[k];
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k2 loop
             } // colouring
         } // face 2
 
         if (domain->m_faceOffset[3] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<NE2; k2+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,NE0);
                         ///////////////
                         // process d //
@@ -6904,22 +7061,22 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double tmp0 = d_p[INDEX2(k, m, numEq)]*w1;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=tmp0;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]=tmp0;
                                 }
                             }
                         }
@@ -6929,27 +7086,30 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,2,numEq)]+=4*w1*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=4*w1*y_p[k];
-                                EM_F[INDEX2(k,6,numEq)]+=4*w1*y_p[k];
-                                EM_F[INDEX2(k,7,numEq)]+=4*w1*y_p[k];
+                                EM_F[INDEX2(k,2,numEq)] = 4*w1*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 4*w1*y_p[k];
+                                EM_F[INDEX2(k,6,numEq)] = 4*w1*y_p[k];
+                                EM_F[INDEX2(k,7,numEq)] = 4*w1*y_p[k];
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k2 loop
             } // colouring
         } // face 3
 
         if (domain->m_faceOffset[4] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<NE1; k1+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,NE0);
                         ///////////////
                         // process d //
@@ -6959,22 +7119,22 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double tmp0 = d_p[INDEX2(k, m, numEq)]*w0;
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=tmp0;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]=tmp0;
                                 }
                             }
                         }
@@ -6984,27 +7144,30 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=4*w0*y_p[k];
-                                EM_F[INDEX2(k,1,numEq)]+=4*w0*y_p[k];
-                                EM_F[INDEX2(k,2,numEq)]+=4*w0*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=4*w0*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 4*w0*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 4*w0*y_p[k];
+                                EM_F[INDEX2(k,2,numEq)] = 4*w0*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 4*w0*y_p[k];
                             }
                         }
                         const index_t firstNode=m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k1 loop
             } // colouring
         } // face 4
 
         if (domain->m_faceOffset[5] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<NE1; k1+=2) {
                     for (index_t k0=0; k0<NE0; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,NE0);
                         ///////////////
                         // process d //
@@ -7014,22 +7177,22 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double tmp0 = d_p[INDEX2(k, m, numEq)]*w0;
-                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp0;
-                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=tmp0;
+                                    EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]=tmp0;
+                                    EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]=tmp0;
                                 }
                             }
                         }
@@ -7039,15 +7202,15 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
                         if (add_EM_F) {
                             const double* y_p=y.getSampleDataRO(e);
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,4,numEq)]+=4*w0*y_p[k];
-                                EM_F[INDEX2(k,5,numEq)]+=4*w0*y_p[k];
-                                EM_F[INDEX2(k,6,numEq)]+=4*w0*y_p[k];
-                                EM_F[INDEX2(k,7,numEq)]+=4*w0*y_p[k];
+                                EM_F[INDEX2(k,4,numEq)] = 4*w0*y_p[k];
+                                EM_F[INDEX2(k,5,numEq)] = 4*w0*y_p[k];
+                                EM_F[INDEX2(k,6,numEq)] = 4*w0*y_p[k];
+                                EM_F[INDEX2(k,7,numEq)] = 4*w0*y_p[k];
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k1 loop
             } // colouring
diff --git a/ripley/src/DefaultAssembler3D.h b/ripley/src/DefaultAssembler3D.h
index 85b6a9f..7586610 100644
--- a/ripley/src/DefaultAssembler3D.h
+++ b/ripley/src/DefaultAssembler3D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/LameAssembler2D.cpp b/ripley/src/LameAssembler2D.cpp
index fea93bd..15abe99 100644
--- a/ripley/src/LameAssembler2D.cpp
+++ b/ripley/src/LameAssembler2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,11 +13,14 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ripley/LameAssembler2D.h>
 #include <ripley/domainhelpers.h>
 
 using namespace std;
-
 using escript::AbstractSystemMatrix;
 using escript::Data;
 
@@ -103,17 +106,24 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
     const double w1 = w2*(-SQRT3 + 2);
     const double w3 = w2*(SQRT3 + 3);
     const double w4 = w2*(-SQRT3 + 3);
-    const bool addEM_S=!d.isEmpty();
-    const bool addEM_F=!y.isEmpty();
+    const bool addEM_S = !d.isEmpty();
+    const bool addEM_F = !y.isEmpty();
     rhs.requireWrite();
+
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4*numEq*numComp, 0);
+        vector<double> EM_F(4*numEq, 0);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<m_NE[1]; k1+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = k1;
                     ///////////////
                     // process d //
@@ -126,20 +136,20 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w2*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=d_0*w0 + d_1*w1;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=d_0*w1 + d_1*w0;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = d_0*w0 + d_1*w1;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = d_0*w1 + d_1*w0;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=4*d_0*w2;
-                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=4*d_0*w2;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = 4*d_0*w2;
+                                    EM_S[INDEX4(k,m,2,0,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,0,2,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = 4*d_0*w2;
                                 }
                             }
                         }
@@ -153,29 +163,32 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,0,numEq)]+=w3*y_0 + w4*y_1;
-                                EM_F[INDEX2(k,2,numEq)]+=w3*y_1 + w4*y_0;
+                                EM_F[INDEX2(k,0,numEq)] = w3*y_0 + w4*y_1;
+                                EM_F[INDEX2(k,2,numEq)] = w3*y_1 + w4*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=6*w2*y_p[k];
-                                EM_F[INDEX2(k,2,numEq)]+=6*w2*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 6*w2*y_p[k];
+                                EM_F[INDEX2(k,2,numEq)] = 6*w2*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=m_NN[0]*k1;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
 
         if (domain->m_faceOffset[1] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring            
 #pragma omp for
                 for (index_t k1=k1_0; k1<m_NE[1]; k1+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = domain->m_faceOffset[1]+k1;
                     ///////////////
                     // process d //
@@ -188,20 +201,20 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w2*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=d_0*w0 + d_1*w1;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=d_0*w1 + d_1*w0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = d_0*w0 + d_1*w1;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = d_0*w1 + d_1*w0;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=4*d_0*w2;
-                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)]+=2*d_0*w2;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=4*d_0*w2;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = 4*d_0*w2;
+                                    EM_S[INDEX4(k,m,3,1,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,1,3,numEq,numComp,4)] = 2*d_0*w2;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = 4*d_0*w2;
                                 }
                             }
                         }
@@ -215,29 +228,32 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,1,numEq)]+=w3*y_0 + w4*y_1;
-                                EM_F[INDEX2(k,3,numEq)]+=w3*y_1 + w4*y_0;
+                                EM_F[INDEX2(k,1,numEq)] = w3*y_0 + w4*y_1;
+                                EM_F[INDEX2(k,3,numEq)] = w3*y_1 + w4*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,1,numEq)]+=6*w2*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=6*w2*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 6*w2*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 6*w2*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=m_NN[0]*(k1+1)-2;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
 
         if (domain->m_faceOffset[2] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
 #pragma omp for
                 for (index_t k0 = k0_0; k0 < m_NE[0]; k0+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = domain->m_faceOffset[2]+k0;
                     ///////////////
                     // process d //
@@ -250,20 +266,20 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w5*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=d_0*w6 + d_1*w7;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=d_0*w7 + d_1*w6;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = d_0*w6 + d_1*w7;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = d_0*w7 + d_1*w6;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)]+=4*d_0*w5;
-                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)]+=4*d_0*w5;
+                                    EM_S[INDEX4(k,m,0,0,numEq,numComp,4)] = 4*d_0*w5;
+                                    EM_S[INDEX4(k,m,1,0,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,0,1,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,1,1,numEq,numComp,4)] = 4*d_0*w5;
                                 }
                             }
                         }
@@ -277,29 +293,32 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,0,numEq)]+=w8*y_0 + w9*y_1;
-                                EM_F[INDEX2(k,1,numEq)]+=w8*y_1 + w9*y_0;
+                                EM_F[INDEX2(k,0,numEq)] = w8*y_0 + w9*y_1;
+                                EM_F[INDEX2(k,1,numEq)] = w8*y_1 + w9*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,0,numEq)]+=6*w5*y_p[k];
-                                EM_F[INDEX2(k,1,numEq)]+=6*w5*y_p[k];
+                                EM_F[INDEX2(k,0,numEq)] = 6*w5*y_p[k];
+                                EM_F[INDEX2(k,1,numEq)] = 6*w5*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
 
         if (domain->m_faceOffset[3] > -1) {
+            if (addEM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (addEM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k0_0=0; k0_0<2; k0_0++) { // colouring
 #pragma omp for
                 for (index_t k0 = k0_0; k0 < m_NE[0]; k0+=2) {
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = domain->m_faceOffset[3]+k0;
                     ///////////////
                     // process d //
@@ -312,20 +331,20 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double d_0 = d_p[INDEX3(k,m,0,numEq,numComp)];
                                     const double d_1 = d_p[INDEX3(k,m,1,numEq,numComp)];
                                     const double tmp0 = w5*(d_0 + d_1);
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=d_0*w6 + d_1*w7;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=tmp0;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=d_0*w7 + d_1*w6;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = d_0*w6 + d_1*w7;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)] = tmp0;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = d_0*w7 + d_1*w6;
                                 }
                              }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
                                 for (index_t m=0; m<numComp; m++) {
                                     const double d_0 = d_p[INDEX2(k, m, numEq)];
-                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)]+=4*d_0*w5;
-                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)]+=2*d_0*w5;
-                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)]+=4*d_0*w5;
+                                    EM_S[INDEX4(k,m,2,2,numEq,numComp,4)] = 4*d_0*w5;
+                                    EM_S[INDEX4(k,m,3,2,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,2,3,numEq,numComp,4)] = 2*d_0*w5;
+                                    EM_S[INDEX4(k,m,3,3,numEq,numComp,4)] = 4*d_0*w5;
                                 }
                             }
                         }
@@ -339,19 +358,19 @@ void LameAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                             for (index_t k=0; k<numEq; k++) {
                                 const double y_0 = y_p[INDEX2(k, 0, numEq)];
                                 const double y_1 = y_p[INDEX2(k, 1, numEq)];
-                                EM_F[INDEX2(k,2,numEq)]+=w8*y_0 + w9*y_1;
-                                EM_F[INDEX2(k,3,numEq)]+=w8*y_1 + w9*y_0;
+                                EM_F[INDEX2(k,2,numEq)] = w8*y_0 + w9*y_1;
+                                EM_F[INDEX2(k,3,numEq)] = w8*y_1 + w9*y_0;
                             }
                         } else { // constant data
                             for (index_t k=0; k<numEq; k++) {
-                                EM_F[INDEX2(k,2,numEq)]+=6*w5*y_p[k];
-                                EM_F[INDEX2(k,3,numEq)]+=6*w5*y_p[k];
+                                EM_F[INDEX2(k,2,numEq)] = 6*w5*y_p[k];
+                                EM_F[INDEX2(k,3,numEq)] = 6*w5*y_p[k];
                             }
                         }
                     }
                     const index_t firstNode=m_NN[0]*(m_NN[1]-2)+k0;
-                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S, addEM_F,
-                            firstNode, numEq, numComp);
+                    domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
+                                          addEM_F, firstNode, numEq, numComp);
                 }
             } // end colouring
         }
@@ -408,24 +427,30 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
     const double w6 = -m_dx[1]/(24*m_dx[0]);
     const double w0 = w6*(SQRT3 + 2);
     const double w4 = w6*(-SQRT3 + 2);
-
+    const bool addEM_S = (!mu.isEmpty() || !lambda.isEmpty() || !B.isEmpty()
+                                        || !C.isEmpty() || !D.isEmpty());
+    const bool addEM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
+
 #pragma omp parallel
     {
+        vector<double> EM_S(4*4*numEq*numComp, 0);
+        vector<double> EM_F(4*numEq, 0);
+
         for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
             for (index_t k1=k1_0; k1 < m_NE[1]; k1+=2) {
                 for (index_t k0=0; k0 < m_NE[0]; ++k0)  {
-                    bool addEM_S=false;
-                    bool addEM_F=false;
-                    vector<double> EM_S(4*4*numEq*numComp, 0);
-                    vector<double> EM_F(4*numEq, 0);
                     const index_t e = k0 + m_NE[0]*k1;
+                    if (addEM_S)
+                        fill(EM_S.begin(), EM_S.end(), 0);
+                    if (addEM_F)
+                        fill(EM_F.begin(), EM_F.end(), 0);
+
                     ///////////////
                     // process A //
                     ///////////////
                     if (!mu.isEmpty() || !lambda.isEmpty()) {
-                        addEM_S = true;
                         if (mu.actsExpanded() || lambda.actsExpanded()) {
                             double A_0000[4] = {0};
                             double A_0011[4] = {0};
@@ -705,7 +730,6 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     // process B //
                     ///////////////
                     if (!B.isEmpty()) {
-                        addEM_S=true;
                         const double* B_p=B.getSampleDataRO(e);
                         if (B.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -781,7 +805,6 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     // process C //
                     ///////////////
                     if (!C.isEmpty()) {
-                        addEM_S=true;
                         const double* C_p=C.getSampleDataRO(e);
                         if (C.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -857,7 +880,6 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     // process D //
                     ///////////////
                     if (!D.isEmpty()) {
-                        addEM_S=true;
                         const double* D_p=D.getSampleDataRO(e);
                         if (D.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -923,7 +945,6 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     // process X //
                     ///////////////
                     if (!X.isEmpty()) {
-                        addEM_F=true;
                         const double* X_p=X.getSampleDataRO(e);
                         if (X.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -971,7 +992,6 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     // process Y //
                     ///////////////
                     if (!Y.isEmpty()) {
-                        addEM_F=true;
                         const double* Y_p=Y.getSampleDataRO(e);
                         if (Y.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -999,7 +1019,7 @@ void LameAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     // add to matrix (if addEM_S) and RHS (if addEM_F)
                     const index_t firstNode=m_NN[0]*k1+k0;
                     domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, addEM_S,
-                            addEM_F, firstNode, numEq, numComp);
+                                          addEM_F, firstNode, numEq, numComp);
                 } // end k0 loop
             } // end k1 loop
         } // end of colouring
diff --git a/ripley/src/LameAssembler2D.h b/ripley/src/LameAssembler2D.h
index b6ac276..749cb67 100644
--- a/ripley/src/LameAssembler2D.h
+++ b/ripley/src/LameAssembler2D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/LameAssembler3D.cpp b/ripley/src/LameAssembler3D.cpp
index 483e60d..db4eec7 100644
--- a/ripley/src/LameAssembler3D.cpp
+++ b/ripley/src/LameAssembler3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ripley/LameAssembler3D.h>
 #include <ripley/domainhelpers.h>
 
@@ -69,6 +72,19 @@ void LameAssembler3D::assemblePDEBoundarySingleReduced(
     throw RipleyException("assemblePDESingle not implemented in LameAssembler3D");
 }
 
+void LameAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+                                        Data& rhs, const DataMap& coefs) const
+{
+    throw RipleyException("assemblePDESystemReduced not implemented in LameAssembler3D");
+}
+
+void LameAssembler3D::assemblePDEBoundarySystemReduced(
+                                        AbstractSystemMatrix* mat,
+                                        Data& rhs, const DataMap& coefs) const
+{
+    throw RipleyException("assemblePDEBoundarySystemReduced not implemented in LameAssembler3D");
+}
+
 void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
@@ -97,18 +113,25 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
     const double w1 = w2*(SQRT3 + 2);
     const double w3 = w2*(-4*SQRT3 + 7);
     const double w4 = w2*(4*SQRT3 + 7);
-    const bool add_EM_S=!d.isEmpty();
-    const bool add_EM_F=!y.isEmpty();
+    const bool add_EM_S = !d.isEmpty();
+    const bool add_EM_F = !y.isEmpty();
     rhs.requireWrite();
+
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8*numEq*numComp, 0);
+        vector<double> EM_F(8*numEq, 0);
+
         if (domain->m_faceOffset[0] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<m_NE[2]; k2+=2) {
                     for (index_t k1=0; k1<m_NE[1]; ++k1) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = INDEX2(k1,k2,m_NE[1]);
                         ///////////////
                         // process d //
@@ -133,44 +156,44 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double tmp8 = w2*(d_0 + d_3);
                                         const double tmp9 = w2*(d_1 + d_2);
                                         const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=d_0*w4 + d_3*w3 + tmp9;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp6 + tmp7;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=d_1*w4 + d_2*w3 + tmp8;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=d_1*w3 + d_2*w4 + tmp8;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=d_0*w3 + d_3*w4 + tmp9;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = d_0*w4 + d_3*w3 + tmp9;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = tmp6 + tmp7;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = d_1*w4 + d_2*w3 + tmp8;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = d_1*w3 + d_2*w4 + tmp8;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = d_0*w3 + d_3*w4 + tmp9;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
                                         const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w2;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=4*wd0;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,6,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,2,4,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,2,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,0,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -188,35 +211,38 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
                                     const double tmp0 = 6*w2*(y_1 + y_2);
                                     const double tmp1 = 6*w2*(y_0 + y_3);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + 6*w0*y_3 + 6*w1*y_0;
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp1 + 6*w0*y_2 + 6*w1*y_1;
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp1 + 6*w0*y_1 + 6*w1*y_2;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                                    EM_F[INDEX2(k,0,numEq)] = tmp0 + 6*w0*y_3 + 6*w1*y_0;
+                                    EM_F[INDEX2(k,2,numEq)] = tmp1 + 6*w0*y_2 + 6*w1*y_1;
+                                    EM_F[INDEX2(k,4,numEq)] = tmp1 + 6*w0*y_1 + 6*w1*y_2;
+                                    EM_F[INDEX2(k,6,numEq)] = tmp0 + 6*w0*y_0 + 6*w1*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,2,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,4,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,6,numEq)]+=36*w2*y_p[k];
+                                    EM_F[INDEX2(k,0,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,2,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,4,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,6,numEq)] = 36*w2*y_p[k];
                                 }
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*k1;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 0
 
         if (domain->m_faceOffset[1] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<m_NE[2]; k2+=2) {
                     for (index_t k1=0; k1<m_NE[1]; ++k1) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[1]+INDEX2(k1,k2,m_NE[1]);
                         ///////////////
                         // process d //
@@ -241,44 +267,44 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double tmp8 = w0*(d_0 + d_1);
                                         const double tmp9 = w1*(d_2 + d_3);
                                         const double tmp10 = w2*(d_0 + d_1 + d_2 + d_3);
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=d_0*w4 + d_3*w3 + tmp7;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=d_1*w4 + d_2*w3 + tmp6;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=d_1*w3 + d_2*w4 + tmp6;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=tmp10;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=d_0*w3 + d_3*w4 + tmp7;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = d_0*w4 + d_3*w3 + tmp7;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = d_1*w4 + d_2*w3 + tmp6;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = d_1*w3 + d_2*w4 + tmp6;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)] = tmp10;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = d_0*w3 + d_3*w4 + tmp7;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
                                         const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w2;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=4*wd0;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,7,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,3,5,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,3,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,1,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -296,35 +322,38 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
                                     const double tmp0 = 6*w2*(y_1 + y_2);
                                     const double tmp1 = 6*w2*(y_0 + y_3);
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp0 + 6*w0*y_3 + 6*w1*y_0;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp1 + 6*w0*y_2 + 6*w1*y_1;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp1 + 6*w0*y_1 + 6*w1*y_2;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp0 + 6*w0*y_0 + 6*w1*y_3;
+                                    EM_F[INDEX2(k,1,numEq)] = tmp0 + 6*w0*y_3 + 6*w1*y_0;
+                                    EM_F[INDEX2(k,3,numEq)] = tmp1 + 6*w0*y_2 + 6*w1*y_1;
+                                    EM_F[INDEX2(k,5,numEq)] = tmp1 + 6*w0*y_1 + 6*w1*y_2;
+                                    EM_F[INDEX2(k,7,numEq)] = tmp0 + 6*w0*y_0 + 6*w1*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,1,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,3,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,5,numEq)]+=36*w2*y_p[k];
-                                    EM_F[INDEX2(k,7,numEq)]+=36*w2*y_p[k];
+                                    EM_F[INDEX2(k,1,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,3,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,5,numEq)] = 36*w2*y_p[k];
+                                    EM_F[INDEX2(k,7,numEq)] = 36*w2*y_p[k];
                                 }
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(k1+1)-2;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k1 loop
                 } // k2 loop
             } // colouring
         } // face 1
 
         if (domain->m_faceOffset[2] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<m_NE[2]; k2+=2) {
                     for (index_t k0=0; k0<m_NE[0]; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[2]+INDEX2(k0,k2,m_NE[0]);
                         ///////////////
                         // process d //
@@ -349,44 +378,44 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double tmp8 = w7*(d_1 + d_2);
                                         const double tmp9 = w5*(d_2 + d_3);
                                         const double tmp10 = w6*(d_0 + d_1);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=d_0*w9 + d_3*w8 + tmp8;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=d_1*w9 + d_2*w8 + tmp6;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=d_1*w8 + d_2*w9 + tmp6;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=tmp7;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=d_0*w8 + d_3*w9 + tmp8;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = d_0*w9 + d_3*w8 + tmp8;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = d_1*w9 + d_2*w8 + tmp6;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = d_1*w8 + d_2*w9 + tmp6;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)] = tmp7;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = d_0*w8 + d_3*w9 + tmp8;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
                                         const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w7;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=4*wd0;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,5,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,1,4,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,1,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,0,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -404,35 +433,38 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
                                     const double tmp0 = 6*w7*(y_1 + y_2);
                                     const double tmp1 = 6*w7*(y_0 + y_3);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + 6*w5*y_3 + 6*w6*y_0;
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp1 + 6*w5*y_2 + 6*w6*y_1;
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp1 + 6*w5*y_1 + 6*w6*y_2;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp0 + 6*w5*y_0 + 6*w6*y_3;
+                                    EM_F[INDEX2(k,0,numEq)] = tmp0 + 6*w5*y_3 + 6*w6*y_0;
+                                    EM_F[INDEX2(k,1,numEq)] = tmp1 + 6*w5*y_2 + 6*w6*y_1;
+                                    EM_F[INDEX2(k,4,numEq)] = tmp1 + 6*w5*y_1 + 6*w6*y_2;
+                                    EM_F[INDEX2(k,5,numEq)] = tmp0 + 6*w5*y_0 + 6*w6*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,1,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,4,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,5,numEq)]+=36*w7*y_p[k];
+                                    EM_F[INDEX2(k,0,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,1,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,4,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,5,numEq)] = 36*w7*y_p[k];
                                 }
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k2 loop
             } // colouring
         } // face 2
 
         if (domain->m_faceOffset[3] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
                 for (index_t k2=k2_0; k2<m_NE[2]; k2+=2) {
                     for (index_t k0=0; k0<m_NE[0]; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[3]+INDEX2(k0,k2,m_NE[0]);
                         ///////////////
                         // process d //
@@ -457,44 +489,44 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double tmp8 = w7*(d_1 + d_2);
                                         const double tmp9 = w5*(d_2 + d_3);
                                         const double tmp10 = w6*(d_0 + d_1);
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=d_0*w9 + d_3*w8 + tmp8;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=d_1*w9 + d_2*w8 + tmp7;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=tmp2 + tmp3;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=d_1*w8 + d_2*w9 + tmp7;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=tmp4;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=d_0*w8 + d_3*w9 + tmp8;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = d_0*w9 + d_3*w8 + tmp8;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = d_1*w9 + d_2*w8 + tmp7;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = tmp2 + tmp3;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = d_1*w8 + d_2*w9 + tmp7;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)] = tmp4;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = d_0*w8 + d_3*w9 + tmp8;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
                                         const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w7;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=4*wd0;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,7,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,3,6,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,3,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,2,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,7,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -512,35 +544,38 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
                                     const double tmp0 = 6*w7*(y_1 + y_2);
                                     const double tmp1 = 6*w7*(y_0 + y_3);
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp0 + 6*w5*y_3 + 6*w6*y_0;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp1 + 6*w5*y_2 + 6*w6*y_1;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp1 + 6*w5*y_1 + 6*w6*y_2;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp0 + 6*w5*y_0 + 6*w6*y_3;
+                                    EM_F[INDEX2(k,2,numEq)] = tmp0 + 6*w5*y_3 + 6*w6*y_0;
+                                    EM_F[INDEX2(k,3,numEq)] = tmp1 + 6*w5*y_2 + 6*w6*y_1;
+                                    EM_F[INDEX2(k,6,numEq)] = tmp1 + 6*w5*y_1 + 6*w6*y_2;
+                                    EM_F[INDEX2(k,7,numEq)] = tmp0 + 6*w5*y_0 + 6*w6*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,2,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,3,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,6,numEq)]+=36*w7*y_p[k];
-                                    EM_F[INDEX2(k,7,numEq)]+=36*w7*y_p[k];
+                                    EM_F[INDEX2(k,2,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,3,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,6,numEq)] = 36*w7*y_p[k];
+                                    EM_F[INDEX2(k,7,numEq)] = 36*w7*y_p[k];
                                 }
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*k2+m_NN[0]*(m_NN[1]-2)+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k2 loop
             } // colouring
         } // face 3
 
         if (domain->m_faceOffset[4] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<m_NE[1]; k1+=2) {
                     for (index_t k0=0; k0<m_NE[0]; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[4]+INDEX2(k0,k1,m_NE[0]);
                         ///////////////
                         // process d //
@@ -565,44 +600,44 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double tmp8 = w11*(d_2 + d_3);
                                         const double tmp9 = w10*(d_2 + d_3);
                                         const double tmp10 = w11*(d_0 + d_1);
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=d_0*w14 + d_3*w13 + tmp3;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=tmp10 + tmp9;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=d_1*w14 + d_2*w13 + tmp6;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=tmp4 + tmp5;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=d_1*w13 + d_2*w14 + tmp6;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=tmp7 + tmp8;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=tmp2;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=tmp0 + tmp1;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=tmp7 + tmp8;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=d_0*w13 + d_3*w14 + tmp3;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = d_0*w14 + d_3*w13 + tmp3;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = tmp10 + tmp9;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = d_1*w14 + d_2*w13 + tmp6;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = tmp4 + tmp5;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = d_1*w13 + d_2*w14 + tmp6;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = tmp7 + tmp8;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)] = tmp2;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = tmp0 + tmp1;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = tmp7 + tmp8;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = d_0*w13 + d_3*w14 + tmp3;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
                                         const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w12;
-                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)]+=4*wd0;
+                                        EM_S[INDEX4(k,m,0,0,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,0,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,0,3,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,1,1,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,1,2,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,1,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,0,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,2,1,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,2,2,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,2,3,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,0,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,3,1,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,2,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,3,3,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -620,35 +655,38 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
                                     const double tmp0 = 6*w12*(y_1 + y_2);
                                     const double tmp1 = 6*w12*(y_0 + y_3);
-                                    EM_F[INDEX2(k,0,numEq)]+=tmp0 + 6*w10*y_3 + 6*w11*y_0;
-                                    EM_F[INDEX2(k,1,numEq)]+=tmp1 + 6*w10*y_2 + 6*w11*y_1;
-                                    EM_F[INDEX2(k,2,numEq)]+=tmp1 + 6*w10*y_1 + 6*w11*y_2;
-                                    EM_F[INDEX2(k,3,numEq)]+=tmp0 + 6*w10*y_0 + 6*w11*y_3;
+                                    EM_F[INDEX2(k,0,numEq)] = tmp0 + 6*w10*y_3 + 6*w11*y_0;
+                                    EM_F[INDEX2(k,1,numEq)] = tmp1 + 6*w10*y_2 + 6*w11*y_1;
+                                    EM_F[INDEX2(k,2,numEq)] = tmp1 + 6*w10*y_1 + 6*w11*y_2;
+                                    EM_F[INDEX2(k,3,numEq)] = tmp0 + 6*w10*y_0 + 6*w11*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,0,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,1,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,2,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,3,numEq)]+=36*w12*y_p[k];
+                                    EM_F[INDEX2(k,0,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,1,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,2,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,3,numEq)] = 36*w12*y_p[k];
                                 }
                             }
                         }
                         const index_t firstNode=m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k1 loop
             } // colouring
         } // face 4
 
         if (domain->m_faceOffset[5] > -1) {
+            if (add_EM_S)
+                fill(EM_S.begin(), EM_S.end(), 0);
+            if (add_EM_F)
+                fill(EM_F.begin(), EM_F.end(), 0);
+
             for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
                 for (index_t k1=k1_0; k1<m_NE[1]; k1+=2) {
                     for (index_t k0=0; k0<m_NE[0]; ++k0) {
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = domain->m_faceOffset[5]+INDEX2(k0,k1,m_NE[0]);
                         ///////////////
                         // process d //
@@ -673,44 +711,44 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         const double tmp8 = w10*(d_0 + d_2);
                                         const double tmp9 = w11*(d_1 + d_3);
                                         const double tmp10 = w12*(d_0 + d_3);
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=d_0*w14 + d_3*w13 + tmp7;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=tmp1 + tmp2;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=tmp3 + tmp4;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=d_1*w14 + d_2*w13 + tmp10;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=tmp1 + tmp2;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=d_1*w13 + d_2*w14 + tmp10;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=tmp0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=tmp8 + tmp9;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=tmp5 + tmp6;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=d_0*w13 + d_3*w14 + tmp7;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = d_0*w14 + d_3*w13 + tmp7;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = tmp1 + tmp2;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = tmp3 + tmp4;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = d_1*w14 + d_2*w13 + tmp10;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = tmp1 + tmp2;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = d_1*w13 + d_2*w14 + tmp10;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)] = tmp0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = tmp8 + tmp9;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = tmp5 + tmp6;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = d_0*w13 + d_3*w14 + tmp7;
                                     }
                                  }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
                                     for (index_t m=0; m<numComp; m++) {
                                         const double wd0 = 4*d_p[INDEX2(k, m, numEq)]*w12;
-                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)]+=4*wd0;
-                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)]+=  wd0;
-                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)]+=2*wd0;
-                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)]+=4*wd0;
+                                        EM_S[INDEX4(k,m,4,4,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,4,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,4,7,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,5,5,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,5,6,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,5,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,4,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,6,5,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,6,6,numEq,numComp,8)] = 4*wd0;
+                                        EM_S[INDEX4(k,m,6,7,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,4,numEq,numComp,8)] =   wd0;
+                                        EM_S[INDEX4(k,m,7,5,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,6,numEq,numComp,8)] = 2*wd0;
+                                        EM_S[INDEX4(k,m,7,7,numEq,numComp,8)] = 4*wd0;
                                     }
                                 }
                             }
@@ -728,23 +766,23 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                     const double y_3 = y_p[INDEX2(k, 3, numEq)];
                                     const double tmp0 = 6*w12*(y_1 + y_2);
                                     const double tmp1 = 6*w12*(y_0 + y_3);
-                                    EM_F[INDEX2(k,4,numEq)]+=tmp0 + 6*w10*y_3 + 6*w11*y_0;
-                                    EM_F[INDEX2(k,5,numEq)]+=tmp1 + 6*w10*y_2 + 6*w11*y_1;
-                                    EM_F[INDEX2(k,6,numEq)]+=tmp1 + 6*w10*y_1 + 6*w11*y_2;
-                                    EM_F[INDEX2(k,7,numEq)]+=tmp0 + 6*w10*y_0 + 6*w11*y_3;
+                                    EM_F[INDEX2(k,4,numEq)] = tmp0 + 6*w10*y_3 + 6*w11*y_0;
+                                    EM_F[INDEX2(k,5,numEq)] = tmp1 + 6*w10*y_2 + 6*w11*y_1;
+                                    EM_F[INDEX2(k,6,numEq)] = tmp1 + 6*w10*y_1 + 6*w11*y_2;
+                                    EM_F[INDEX2(k,7,numEq)] = tmp0 + 6*w10*y_0 + 6*w11*y_3;
                                 }
                             } else { // constant data
                                 for (index_t k=0; k<numEq; k++) {
-                                    EM_F[INDEX2(k,4,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,5,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,6,numEq)]+=36*w12*y_p[k];
-                                    EM_F[INDEX2(k,7,numEq)]+=36*w12*y_p[k];
+                                    EM_F[INDEX2(k,4,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,5,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,6,numEq)] = 36*w12*y_p[k];
+                                    EM_F[INDEX2(k,7,numEq)] = 36*w12*y_p[k];
                                 }
                             }
                         }
                         const index_t firstNode=m_NN[0]*m_NN[1]*(m_NN[2]-2)+m_NN[0]*k1+k0;
-                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F, add_EM_S,
-                                add_EM_F, firstNode, numEq, numComp);
+                        domain->addToMatrixAndRHS(mat, rhs, EM_S, EM_F,
+                                add_EM_S, add_EM_F, firstNode, numEq, numComp);
                     } // k0 loop
                 } // k1 loop
             } // colouring
@@ -752,19 +790,6 @@ void LameAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
     } // end of parallel region
 }
 
-void LameAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
-                                        Data& rhs, const DataMap& coefs) const
-{
-    throw RipleyException("assemblePDESystemReduced not implemented in LameAssembler3D");
-}
-
-void LameAssembler3D::assemblePDEBoundarySystemReduced(
-                                        AbstractSystemMatrix* mat,
-                                        Data& rhs, const DataMap& coefs) const
-{
-    throw RipleyException("assemblePDEBoundarySystemReduced not implemented in LameAssembler3D");
-}
-
 void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                                         const DataMap& coefs) const
 {
@@ -860,25 +885,31 @@ void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
     const double w14 = w27*(-SQRT3 - 2);
     const double w28 = w27*(-4*SQRT3 + 7);
     const double w29 = w27*(4*SQRT3 + 7);
-
+    const bool add_EM_S = (!mu.isEmpty() || !lambda.isEmpty() || !B.isEmpty()
+                                         || !C.isEmpty() || !D.isEmpty());
+    const bool add_EM_F = (!X.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
+
 #pragma omp parallel
     {
+        vector<double> EM_S(8*8*numEq*numComp, 0);
+        vector<double> EM_F(8*numEq, 0);
+
         for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
             for (index_t k2=k2_0; k2<m_NE[2]; k2+=2) {
                 for (index_t k1=0; k1<m_NE[1]; ++k1) {
                     for (index_t k0=0; k0<m_NE[0]; ++k0)  {
-                        bool add_EM_S=false;
-                        bool add_EM_F=false;
-                        vector<double> EM_S(8*8*numEq*numComp, 0);
-                        vector<double> EM_F(8*numEq, 0);
                         const index_t e = k0 + m_NE[0]*k1 + m_NE[0]*m_NE[1]*k2;
+                        if (add_EM_S)
+                            fill(EM_S.begin(), EM_S.end(), 0);
+                        if (add_EM_F)
+                            fill(EM_F.begin(), EM_F.end(), 0);
+
                         ///////////////
                         // process A //
                         ///////////////
                         if (!mu.isEmpty() || !lambda.isEmpty()) {
-                            add_EM_S = true;
                             if (mu.actsExpanded() || lambda.actsExpanded()) {
                                 double A_0000[8] = {0};
                                 double A_0011[8] = {0};
@@ -3158,7 +3189,6 @@ void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                         // process B //
                         ///////////////
                         if (!B.isEmpty()) {
-                            add_EM_S=true;
                             const double* B_p=B.getSampleDataRO(e);
                             if (B.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -3595,7 +3625,6 @@ void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                         // process C //
                         ///////////////
                         if (!C.isEmpty()) {
-                            add_EM_S=true;
                             const double* C_p=C.getSampleDataRO(e);
                             if (C.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -4032,7 +4061,6 @@ void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                         // process D //
                         ///////////////
                         if (!D.isEmpty()) {
-                            add_EM_S=true;
                             const double* D_p=D.getSampleDataRO(e);
                             if (D.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -4246,7 +4274,6 @@ void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                         // process X //
                         ///////////////
                         if (!X.isEmpty()) {
-                            add_EM_F=true;
                             const double* X_p=X.getSampleDataRO(e);
                             if (X.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -4363,7 +4390,6 @@ void LameAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                         // process Y //
                         ///////////////
                         if (!Y.isEmpty()) {
-                            add_EM_F=true;
                             const double* Y_p=Y.getSampleDataRO(e);
                             if (Y.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
diff --git a/ripley/src/LameAssembler3D.h b/ripley/src/LameAssembler3D.h
index 5c061a6..6bc505e 100644
--- a/ripley/src/LameAssembler3D.h
+++ b/ripley/src/LameAssembler3D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/MultiBrick.cpp b/ripley/src/MultiBrick.cpp
new file mode 100644
index 0000000..c492176
--- /dev/null
+++ b/ripley/src/MultiBrick.cpp
@@ -0,0 +1,1563 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+#include <ripley/MultiBrick.h>
+#include <ripley/blocktools.h>
+#include <ripley/domainhelpers.h>
+#include <paso/SystemMatrix.h>
+#include <esysUtils/esysFileWriter.h>
+#include <esysUtils/EsysRandom.h>
+#include <escript/DataFactory.h>
+#include <escript/FunctionSpaceFactory.h>
+#include <boost/scoped_array.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>	// for isnan
+
+#ifdef USE_NETCDF
+#include <netcdfcpp.h>
+#endif
+
+#if USE_SILO
+#include <silo.h>
+#ifdef ESYS_MPI
+#include <pmpio.h>
+#endif
+#endif
+
+#define FIRST_QUAD 0.21132486540518711775
+#define SECOND_QUAD 0.78867513459481288225
+
+#include <iomanip>
+#include <limits>
+
+
+
+namespace bp = boost::python;
+using esysUtils::FileWriter;
+using escript::AbstractSystemMatrix;
+
+using std::vector;
+using std::string;
+using std::min;
+using std::max;
+using std::copy;
+using std::ios;
+using std::fill;
+
+namespace ripley {
+
+inline int indexOfMax(dim_t a, dim_t b, dim_t c)
+{
+    if (a > b) {
+        if (c > a) {
+            return 2;
+        }
+        return 0;
+    } else if (b > c) {
+        return 1;
+    }
+    return 2;
+}
+
+MultiBrick::MultiBrick(dim_t n0, dim_t n1, dim_t n2, double x0, double y0, double z0,
+             double x1, double y1, double z1, int d0, int d1, int d2,
+             const vector<double>& points, const vector<int>& tags,
+             const TagMap& tagnamestonums,
+             escript::SubWorld_ptr w,
+             unsigned int subdivisions
+         ) :
+    Brick(n0, n1, n2, x0, y0, z0, x1, y1, z1, d0, d1, d2, points, tags, tagnamestonums, w),
+    m_subdivisions(subdivisions)
+{
+    if (m_mpiInfo->size != 1)
+        throw RipleyException("Multiresolution domains don't currently support multiple processes");
+
+    if (subdivisions == 0 || (subdivisions & (subdivisions - 1)) != 0)
+        throw RipleyException("Element subdivisions must be a power of two");
+
+    if (d0 == 0 || d1 == 0)
+        throw RipleyException("Domain subdivisions must be positive");
+
+    dim_t oldNN[3] = {0};
+
+    for (int i = 0; i < 3; i++) {
+        m_NE[i] *= subdivisions;
+        oldNN[i] = m_NN[i];
+        m_NN[i] = m_NE[i] + 1;
+        m_gNE[i] *= subdivisions;
+        m_ownNE[i] *= subdivisions;
+        m_dx[i] /= subdivisions;
+        m_faceCount[i] *= subdivisions;
+        m_faceCount[2+i] *= subdivisions;
+    }
+
+    // bottom-left node is at (offset0,offset1) in global mesh
+    m_offset[0] = m_gNE[0]*subdivisions/d0*(m_mpiInfo->rank%d0);
+    m_offset[1] = m_gNE[1]*subdivisions/d1*(m_mpiInfo->rank/d0);
+    m_offset[2] = m_gNE[2]*subdivisions/d2*(m_mpiInfo->rank/(d0*d1));
+    populateSampleIds();
+    
+    const dim_t nDirac = m_diracPoints.size();
+#pragma omp parallel for
+    for (int i = 0; i < nDirac; i++) {
+        const dim_t node = m_diracPoints[i].node;
+        const dim_t x = node % oldNN[0];
+        const dim_t y = (node % (oldNN[0]*oldNN[1])) / oldNN[0];
+        const dim_t z = node / (oldNN[0]*oldNN[1]);
+        m_diracPoints[i].node = INDEX3(x*subdivisions, y*subdivisions, z*subdivisions,
+                m_NN[0], m_NN[1]);
+        m_diracPointNodeIDs[i] = m_diracPoints[i].node;
+    }
+}
+
+MultiBrick::~MultiBrick()
+{
+}
+
+
+void MultiBrick::validateInterpolationAcross(int fsType_source,
+        const escript::AbstractDomain& domain, int fsType_target) const
+{
+    const MultiBrick *other = dynamic_cast<const MultiBrick *>(&domain);
+    if (other == NULL)
+        throw RipleyException("Invalid interpolation: domains must both be instances of MultiBrick");
+
+    const double *len = other->getLength();
+    const int *subdivs = other->getNumSubdivisionsPerDim();
+    const int *elements = other->getNumElementsPerDim();
+    const unsigned int level = other->getNumSubdivisionsPerElement();
+    const unsigned int factor = m_subdivisions > level ? m_subdivisions/level : level/m_subdivisions;
+    if ((factor & (factor - 1)) != 0) //factor == 2**x
+        throw RipleyException("Invalid interpolation: elemental subdivisions of each domain must be powers of two");
+
+    if (other->getMPIComm() != m_mpiInfo->comm)
+        throw RipleyException("Invalid interpolation: Domains are on different communicators");
+
+    for (int i = 0; i < m_numDim; i++) {
+        if (m_length[i] != len[i])
+            throw RipleyException("Invalid interpolation: domain length mismatch");
+        if (m_NX[i] != subdivs[i])
+            throw RipleyException("Invalid interpolation: domain process subdivision mismatch");
+        if (m_subdivisions > level) {
+            if (m_ownNE[i]/elements[i] != factor)
+                throw RipleyException("Invalid interpolation: element factor mismatch");
+        } else {
+            if (elements[i]/m_ownNE[i] != factor)
+                throw RipleyException("Invalid interpolation: element factor mismatch");
+        }
+    }
+}
+
+void MultiBrick::interpolateNodesToNodesFiner(const escript::Data& source,
+        escript::Data& target, const MultiBrick& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t NN0 = m_NN[0], NN1 = m_NN[1], NN2 = m_NN[2], *otherNN = other.getNumNodesPerDim();
+    const dim_t numComp = source.getDataPointSize();
+#pragma omp parallel for
+    for (dim_t nz = 0; nz < NN2 - 1; nz++) { //source nodes
+        for (dim_t ny = 0; ny < NN1 - 1; ny++) {
+            for (dim_t nx = 0; nx < NN0 - 1; nx++) {
+                const double *x0y0z0 = source.getSampleDataRO(INDEX3(nx,   ny,   nz, NN0, NN1));
+                const double *x0y1z0 = source.getSampleDataRO(INDEX3(nx,   ny+1, nz, NN0, NN1));
+                const double *x1y0z0 = source.getSampleDataRO(INDEX3(nx+1, ny,   nz, NN0, NN1));
+                const double *x1y1z0 = source.getSampleDataRO(INDEX3(nx+1, ny+1, nz, NN0, NN1));
+                const double *x0y0z1 = source.getSampleDataRO(INDEX3(nx,   ny,   nz+1, NN0, NN1));
+                const double *x0y1z1 = source.getSampleDataRO(INDEX3(nx,   ny+1, nz+1, NN0, NN1));
+                const double *x1y0z1 = source.getSampleDataRO(INDEX3(nx+1, ny,   nz+1, NN0, NN1));
+                const double *x1y1z1 = source.getSampleDataRO(INDEX3(nx+1, ny+1, nz+1, NN0, NN1));
+                const double origin[3] = {getLocalCoordinate(nx, 0),
+                                          getLocalCoordinate(ny, 1),
+                                          getLocalCoordinate(nz, 2)};
+                for (int sz = 0; sz < scaling + 1; sz++) { //target nodes                
+                    const double z = (other.getLocalCoordinate(nz*scaling+sz, 2) - origin[2]) / m_dx[2];
+                    for (int sy = 0; sy < scaling + 1; sy++) {
+                        const double y = (other.getLocalCoordinate(ny*scaling+sy, 1) - origin[1]) / m_dx[1];
+                        for (int sx = 0; sx < scaling + 1; sx++) {
+                            const double x = (other.getLocalCoordinate(nx*scaling+sx, 0) - origin[0]) / m_dx[0];
+                            double *out = target.getSampleDataRW(INDEX3(nx*scaling+sx, ny*scaling+sy, nz*scaling+sz, otherNN[0], otherNN[1]));
+                            for (int comp = 0; comp < numComp; comp++) {
+                                out[comp] = x0y0z0[comp]*(1-x)*(1-y)*(1-z) + x1y0z0[comp]*x*(1-y)*(1-z) + x0y1z0[comp]*(1-x)*y*(1-z) + x1y1z0[comp]*x*y*(1-z)
+                                          + x0y0z1[comp]*(1-x)*(1-y)*z     + x1y0z1[comp]*x*(1-y)*z     + x0y1z1[comp]*(1-x)*y*z     + x1y1z1[comp]*x*y*z;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiBrick::interpolateReducedToElementsFiner(const escript::Data& source,
+        escript::Data& target, const MultiBrick& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t numComp = source.getDataPointSize();
+    //for each of ours
+#pragma omp parallel for
+    for (dim_t ez = 0; ez < m_NE[2]; ez++) {
+        for (dim_t ey = 0; ey < m_NE[1]; ey++) {
+            for (dim_t ex = 0; ex < m_NE[0]; ex++) {
+                const double *in = source.getSampleDataRO(INDEX3(ex, ey, ez, m_NE[0], m_NE[1]));
+                //for each subelement
+                for (dim_t sz = 0; sz < scaling; sz++) {
+                    const dim_t tz = ez*scaling + sz;
+                    for (dim_t sy = 0; sy < scaling; sy++) {
+                        const dim_t ty = ey*scaling + sy;
+                        for (dim_t sx = 0; sx < scaling; sx++) {
+                            const dim_t tx = ex*scaling + sx;
+                            double *out = target.getSampleDataRW(INDEX3(tx, ty, tz, m_NE[0]*scaling, m_NE[1]*scaling));
+                            for (dim_t comp = 0; comp < numComp; comp++) {
+                                const double quadvalue = in[comp];
+                                for (int i = 0; i < 8; i++) {
+                                    out[comp + i*numComp] = quadvalue;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiBrick::interpolateReducedToReducedFiner(const escript::Data& source,
+        escript::Data& target, const MultiBrick& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t numComp = source.getDataPointSize();
+    //for each of ours
+#pragma omp parallel for
+    for (dim_t ey = 0; ey < m_NE[1]; ey++) {
+        for (dim_t ex = 0; ex < m_NE[0]; ex++) {
+            const double *in = source.getSampleDataRO(ex + ey*m_NE[0]);
+            //for each subelement
+            for (dim_t sy = 0; sy < scaling; sy++) {
+                const dim_t ty = ey*scaling + sy;
+                for (dim_t sx = 0; sx < scaling; sx++) {
+                    const dim_t tx = ex*scaling + sx;
+                    double *out = target.getSampleDataRW(tx + ty*m_NE[0]*scaling);
+                    for (dim_t comp = 0; comp < numComp; comp++) {
+                        out[comp] = in[comp];
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiBrick::interpolateNodesToElementsFiner(const escript::Data& source,
+        escript::Data& target, const MultiBrick& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t NE0 = m_NE[0], NE1 = m_NE[1], NE2 = m_NE[2], *theirNE = other.getNumElementsPerDim();
+    const dim_t numComp = source.getDataPointSize();
+#pragma omp parallel for
+    for (dim_t ez = 0; ez < NE2; ez++) { //source nodes
+        for (dim_t ey = 0; ey < NE1; ey++) {
+            for (dim_t ex = 0; ex < NE0; ex++) {
+                const double *points[8] = {
+                        source.getSampleDataRO(INDEX3(ex,   ey,   ez, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex+1, ey,   ez, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex,   ey+1, ez, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex+1, ey+1, ez, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex,   ey,   ez+1, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex+1, ey,   ez+1, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex,   ey+1, ez+1, NE0+1, NE1+1)),
+                        source.getSampleDataRO(INDEX3(ex+1, ey+1, ez+1, NE0+1, NE1+1)),
+                    };
+                const double origin[3] = {getLocalCoordinate(ex, 0),
+                                          getLocalCoordinate(ey, 1),
+                                          getLocalCoordinate(ez, 2)
+                                          };
+                for (int sz = 0; sz < scaling; sz++) { //target elements
+                    for (int sy = 0; sy < scaling; sy++) {
+                        for (int sx = 0; sx < scaling; sx++) {
+                            const double x1 = (other.getLocalCoordinate(ex*scaling+sx, 0) - origin[0]) / m_dx[0] + FIRST_QUAD/scaling;
+                            const double x2 = x1 + (SECOND_QUAD - FIRST_QUAD)/scaling;
+                            const double y1 = (other.getLocalCoordinate(ey*scaling+sy, 1) - origin[1]) / m_dx[1] + FIRST_QUAD/scaling;
+                            const double y2 = y1 + (SECOND_QUAD - FIRST_QUAD)/scaling;
+                            const double z1 = (other.getLocalCoordinate(ez*scaling+sz, 2) - origin[2]) / m_dx[2] + FIRST_QUAD/scaling;
+                            const double z2 = z1 + (SECOND_QUAD - FIRST_QUAD)/scaling;
+                            double *out = target.getSampleDataRW(INDEX3(ex*scaling+sx, ey*scaling+sy, ez*scaling+sz, theirNE[0], theirNE[1]));
+                            for (int comp = 0; comp < numComp; comp++) {
+                                out[INDEX4(comp, 0, 0, 0, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x1)*(1-y1)*(1-z1)
+                                            + points[1][comp]*x1*(1-y1)*(1-z1) 
+                                            + points[2][comp]*(1-x1)*y1*(1-z1)
+                                            + points[3][comp]*x1*y1*(1-z1)
+                                            + points[4][comp]*(1-x1)*(1-y1)*z1
+                                            + points[5][comp]*x1*(1-y1)*z1 
+                                            + points[6][comp]*(1-x1)*y1*z1
+                                            + points[7][comp]*x1*y1*z1;
+                                out[INDEX4(comp, 1, 0, 0, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x2)*(1-y1)*(1-z1)
+                                            + points[1][comp]*x2*(1-y1)*(1-z1) 
+                                            + points[2][comp]*(1-x2)*y1*(1-z1)
+                                            + points[3][comp]*x2*y1*(1-z1)
+                                            + points[4][comp]*(1-x2)*(1-y1)*z1
+                                            + points[5][comp]*x2*(1-y1)*z1 
+                                            + points[6][comp]*(1-x2)*y1*z1
+                                            + points[7][comp]*x2*y1*z1;
+                                out[INDEX4(comp, 0, 1, 0, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x1)*(1-y2)*(1-z1)
+                                            + points[1][comp]*x1*(1-y2)*(1-z1) 
+                                            + points[2][comp]*(1-x1)*y2*(1-z1)
+                                            + points[3][comp]*x1*y2*(1-z1)
+                                            + points[4][comp]*(1-x1)*(1-y2)*z1
+                                            + points[5][comp]*x1*(1-y2)*z1 
+                                            + points[6][comp]*(1-x1)*y2*z1
+                                            + points[7][comp]*x1*y2*z1;
+                                out[INDEX4(comp, 1, 1, 0, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x2)*(1-y2)*(1-z1)
+                                            + points[1][comp]*x2*(1-y2)*(1-z1) 
+                                            + points[2][comp]*(1-x2)*y2*(1-z1)
+                                            + points[3][comp]*x2*y2*(1-z1)
+                                            + points[4][comp]*(1-x2)*(1-y2)*z1
+                                            + points[5][comp]*x2*(1-y2)*z1 
+                                            + points[6][comp]*(1-x2)*y2*z1
+                                            + points[7][comp]*x2*y2*z1;
+                                out[INDEX4(comp, 0, 0, 1, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x1)*(1-y1)*(1-z2)
+                                            + points[1][comp]*x1*(1-y1)*(1-z2) 
+                                            + points[2][comp]*(1-x1)*y1*(1-z2)
+                                            + points[3][comp]*x1*y1*(1-z2)
+                                            + points[4][comp]*(1-x1)*(1-y1)*z2
+                                            + points[5][comp]*x1*(1-y1)*z2 
+                                            + points[6][comp]*(1-x1)*y1*z2
+                                            + points[7][comp]*x1*y1*z2;
+                                out[INDEX4(comp, 1, 0, 1, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x2)*(1-y1)*(1-z2)
+                                            + points[1][comp]*x2*(1-y1)*(1-z2) 
+                                            + points[2][comp]*(1-x2)*y1*(1-z2)
+                                            + points[3][comp]*x2*y1*(1-z2)
+                                            + points[4][comp]*(1-x2)*(1-y1)*z2
+                                            + points[5][comp]*x2*(1-y1)*z2 
+                                            + points[6][comp]*(1-x2)*y1*z2
+                                            + points[7][comp]*x2*y1*z2;
+                                out[INDEX4(comp, 0, 1, 1, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x1)*(1-y2)*(1-z2)
+                                            + points[1][comp]*x1*(1-y2)*(1-z2) 
+                                            + points[2][comp]*(1-x1)*y2*(1-z2)
+                                            + points[3][comp]*x1*y2*(1-z2)
+                                            + points[4][comp]*(1-x1)*(1-y2)*z2
+                                            + points[5][comp]*x1*(1-y2)*z2 
+                                            + points[6][comp]*(1-x1)*y2*z2
+                                            + points[7][comp]*x1*y2*z2;
+                                out[INDEX4(comp, 1, 1, 1, numComp, 2, 2)] = 
+                                              points[0][comp]*(1-x2)*(1-y2)*(1-z2)
+                                            + points[1][comp]*x2*(1-y2)*(1-z2) 
+                                            + points[2][comp]*(1-x2)*y2*(1-z2)
+                                            + points[3][comp]*x2*y2*(1-z2)
+                                            + points[4][comp]*(1-x2)*(1-y2)*z2
+                                            + points[5][comp]*x2*(1-y2)*z2 
+                                            + points[6][comp]*(1-x2)*y2*z2
+                                            + points[7][comp]*x2*y2*z2;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiBrick::interpolateElementsToElementsCoarser(const escript::Data& source,
+        escript::Data& target, const MultiBrick& other) const
+{
+    const int scaling = m_subdivisions/other.getNumSubdivisionsPerElement();
+    const double scaling_volume = (1./scaling)*(1./scaling)*(1./scaling);
+    const dim_t *theirNE = other.getNumElementsPerDim();
+    const dim_t numComp = source.getDataPointSize();
+
+    std::vector<double> points(scaling*2, 0);
+    std::vector<double> first_lagrange(scaling*2, 1);
+    std::vector<double> second_lagrange(scaling*2, 1);
+    
+    for (int i = 0; i < scaling*2; i+=2) {
+        points[i] = (i/2 + FIRST_QUAD)/scaling;
+        points[i+1] = (i/2 + SECOND_QUAD)/scaling;
+    }
+    
+    for (int i = 0; i < scaling*2; i++) {
+        first_lagrange[i] = (points[i] - SECOND_QUAD) / (FIRST_QUAD - SECOND_QUAD);
+        second_lagrange[i] = (points[i] - FIRST_QUAD) / (SECOND_QUAD - FIRST_QUAD);
+    }
+    
+    //for each of theirs
+#pragma omp parallel for
+    for (dim_t tz = 0; tz < theirNE[2]; tz++) {
+        for (dim_t ty = 0; ty < theirNE[1]; ty++) {
+            for (dim_t tx = 0; tx < theirNE[0]; tx++) {
+                double *out = target.getSampleDataRW(INDEX3(tx, ty, tz, theirNE[0], theirNE[1]));
+                //for each subelement
+                for (dim_t sz = 0; sz < scaling; sz++) {
+                    const dim_t ez = tz*scaling + sz;
+                    for (dim_t sy = 0; sy < scaling; sy++) {
+                        const dim_t ey = ty*scaling + sy;
+                        for (dim_t sx = 0; sx < scaling; sx++) {
+                            const dim_t ex = tx*scaling + sx;
+                            const double *in = source.getSampleDataRO(INDEX3(ex, ey, ez, m_NE[0], m_NE[1]));
+                            for (int quad = 0; quad < 8; quad++) {
+                                int lx = sx*2 + quad%2;
+                                int ly = sy*2 + (quad%4)/2;
+                                int lz = sz*2 + quad/4;
+                                for (dim_t comp = 0; comp < numComp; comp++) {
+                                    const double quadvalue = scaling_volume * in[comp + quad*numComp];
+                                    out[INDEX4(comp, 0, 0, 0, numComp, 2, 2)] += quadvalue * first_lagrange[lx] * first_lagrange[ly] * first_lagrange[lz];
+                                    out[INDEX4(comp, 1, 0, 0, numComp, 2, 2)] += quadvalue * second_lagrange[lx] * first_lagrange[ly] * first_lagrange[lz];
+                                    out[INDEX4(comp, 0, 1, 0, numComp, 2, 2)] += quadvalue * first_lagrange[lx] * second_lagrange[ly] * first_lagrange[lz];
+                                    out[INDEX4(comp, 1, 1, 0, numComp, 2, 2)] += quadvalue * second_lagrange[lx] * second_lagrange[ly] * first_lagrange[lz];
+                                    out[INDEX4(comp, 0, 0, 1, numComp, 2, 2)] += quadvalue * first_lagrange[lx] * first_lagrange[ly] * second_lagrange[lz];
+                                    out[INDEX4(comp, 1, 0, 1, numComp, 2, 2)] += quadvalue * second_lagrange[lx] * first_lagrange[ly] * second_lagrange[lz];
+                                    out[INDEX4(comp, 0, 1, 1, numComp, 2, 2)] += quadvalue * first_lagrange[lx] * second_lagrange[ly] * second_lagrange[lz];
+                                    out[INDEX4(comp, 1, 1, 1, numComp, 2, 2)] += quadvalue * second_lagrange[lx] * second_lagrange[ly] * second_lagrange[lz];
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+void MultiBrick::interpolateElementsToElementsFiner(const escript::Data& source,
+        escript::Data& target, const MultiBrick& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t numComp = source.getDataPointSize();
+
+    std::vector<double> points(scaling*2, 0);
+    std::vector<double> lagranges(scaling*4, 1);
+
+    for (int i = 0; i < scaling*2; i+=2) {
+        points[i] = (i/2 + FIRST_QUAD)/scaling;
+        points[i+1] = (i/2 + SECOND_QUAD)/scaling;
+    }
+    for (int i = 0; i < scaling*2; i++) {
+        lagranges[i] = (points[i] - SECOND_QUAD) / (FIRST_QUAD - SECOND_QUAD);
+        lagranges[i + 2*scaling] = (points[i] - FIRST_QUAD) / (SECOND_QUAD - FIRST_QUAD);
+    }
+    //for each of ours
+#pragma omp parallel for
+    for (dim_t ez = 0; ez < m_NE[2]; ez++) {
+        for (dim_t ey = 0; ey < m_NE[1]; ey++) {
+            for (dim_t ex = 0; ex < m_NE[0]; ex++) {
+                const double *in = source.getSampleDataRO(INDEX3(ex, ey, ez, m_NE[0], m_NE[1]));
+                //for each subelement
+                for (dim_t sz = 0; sz < scaling; sz++) {
+                    const dim_t tz = ez*scaling + sz;
+                    for (dim_t sy = 0; sy < scaling; sy++) {
+                        const dim_t ty = ey*scaling + sy;
+                        for (dim_t sx = 0; sx < scaling; sx++) {
+                            const dim_t tx = ex*scaling + sx;
+                            double *out = target.getSampleDataRW(INDEX3(tx, ty, tz, m_NE[0]*scaling, m_NE[1]*scaling));
+                            for (int quad = 0; quad < 8; quad++) {
+                                const int lx = scaling*2*(quad%2) + sx*2;
+                                const int ly = scaling*2*((quad%4)/2) + sy*2;
+                                const int lz = scaling*2*(quad/4) + sz*2;
+                                for (dim_t comp = 0; comp < numComp; comp++) {
+                                    const double quadvalue = in[comp + quad*numComp];
+                                    out[INDEX4(comp, 0, 0, 0, numComp, 2, 2)] += quadvalue * lagranges[lx] * lagranges[ly] * lagranges[lz];
+                                    out[INDEX4(comp, 0, 1, 0, numComp, 2, 2)] += quadvalue * lagranges[lx] * lagranges[ly+1] * lagranges[lz];
+                                    out[INDEX4(comp, 1, 0, 0, numComp, 2, 2)] += quadvalue * lagranges[lx+1] * lagranges[ly] * lagranges[lz];
+                                    out[INDEX4(comp, 1, 1, 0, numComp, 2, 2)] += quadvalue * lagranges[lx+1] * lagranges[ly+1] * lagranges[lz];
+                                    out[INDEX4(comp, 0, 0, 1, numComp, 2, 2)] += quadvalue * lagranges[lx] * lagranges[ly] * lagranges[lz+1];
+                                    out[INDEX4(comp, 0, 1, 1, numComp, 2, 2)] += quadvalue * lagranges[lx] * lagranges[ly+1] * lagranges[lz+1];
+                                    out[INDEX4(comp, 1, 0, 1, numComp, 2, 2)] += quadvalue * lagranges[lx+1] * lagranges[ly] * lagranges[lz+1];
+                                    out[INDEX4(comp, 1, 1, 1, numComp, 2, 2)] += quadvalue * lagranges[lx+1] * lagranges[ly+1] * lagranges[lz+1];
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiBrick::interpolateAcross(escript::Data& target,
+                                     const escript::Data& source) const
+{
+    const MultiBrick *other =
+                dynamic_cast<const MultiBrick *>(target.getDomain().get());
+    if (other == NULL)
+        throw RipleyException("Invalid interpolation: Domains must both be instances of MultiBrick");
+    //shouldn't ever happen, but I want to know if it does
+    if (other == this)
+        throw RipleyException("interpolateAcross: this domain is the target");
+        
+    validateInterpolationAcross(source.getFunctionSpace().getTypeCode(),
+            *(target.getDomain().get()), target.getFunctionSpace().getTypeCode());
+    int fsSource = source.getFunctionSpace().getTypeCode();
+    int fsTarget = target.getFunctionSpace().getTypeCode();
+
+    std::stringstream msg;
+    msg << "Invalid interpolation: interpolation not implemented for function space "
+        << functionSpaceTypeAsString(fsSource)
+        << " -> "
+        << functionSpaceTypeAsString(fsTarget);
+    if (other->getNumSubdivisionsPerElement() > getNumSubdivisionsPerElement()) {
+        switch (fsSource) {
+            case Nodes:
+                switch (fsTarget) {
+                    case Nodes:
+                    case ReducedNodes:
+                    case DegreesOfFreedom:
+                    case ReducedDegreesOfFreedom:
+                        interpolateNodesToNodesFiner(source, target, *other);
+                        return;
+                    case Elements:
+                        interpolateNodesToElementsFiner(source, target, *other);
+                        return;
+                }
+                break;
+            case Elements:
+                switch (fsTarget) {
+                    case Elements:
+                        interpolateElementsToElementsFiner(source, target, *other);
+                        return;
+                }
+                break;
+            case ReducedElements:
+                switch (fsTarget) {
+                    case Elements:
+                        interpolateReducedToElementsFiner(source, target, *other);
+                        return;
+                }
+                break;
+        }
+        msg << " when target is a finer mesh";
+    } else {
+        switch (fsSource) {
+            case Nodes:
+                switch (fsTarget) {
+                    case Elements:
+                        escript::Data elements=escript::Vector(0., escript::function(*this), true);
+                        interpolateNodesOnElements(elements, source, false);
+                        interpolateElementsToElementsCoarser(elements, target, *other);
+                        return;
+                }
+                break;
+            case Elements:
+                switch (fsTarget) {
+                    case Elements:
+                        interpolateElementsToElementsCoarser(source, target, *other);
+                        return;
+                }
+                break;
+        }
+        msg << " when target is a coarser mesh";
+    }
+    throw RipleyException(msg.str());
+}
+
+string MultiBrick::getDescription() const
+{
+    return "ripley::MultiBrick";
+}
+
+bool MultiBrick::operator==(const AbstractDomain& other) const
+{
+    const MultiBrick* o=dynamic_cast<const MultiBrick*>(&other);
+    if (o) {
+        return (RipleyDomain::operator==(other) &&
+                m_gNE[0]==o->m_gNE[0] && m_gNE[1]==o->m_gNE[1] && m_gNE[2]==o->m_gNE[2]
+                && m_origin[0]==o->m_origin[0] && m_origin[1]==o->m_origin[1] && m_origin[2]==o->m_origin[2]
+                && m_length[0]==o->m_length[0] && m_length[1]==o->m_length[1] && m_length[2]==o->m_length[2]
+                && m_NX[0]==o->m_NX[0] && m_NX[1]==o->m_NX[1] && m_NX[2]==o->m_NX[2]
+                && m_subdivisions == o->m_subdivisions);
+    }
+
+    return false;
+}
+
+void MultiBrick::readNcGrid(escript::Data& out, string filename, string varname,
+            const ReaderParameters& params) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiBricks cannot read datafiles");
+    Brick::readNcGrid(out, filename, varname, params);
+}
+
+void MultiBrick::readBinaryGrid(escript::Data& out, string filename,
+                               const ReaderParameters& params) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiBricks cannot read datafiles");
+    Brick::readBinaryGrid(out, filename, params);
+}
+
+#ifdef USE_BOOSTIO
+void MultiBrick::readBinaryGridFromZipped(escript::Data& out, string filename,
+                               const ReaderParameters& params) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiBricks cannot read datafiles");
+    Brick::readBinaryGridFromZipped(out, filename, params);
+}
+#endif
+
+void MultiBrick::writeBinaryGrid(const escript::Data& in, string filename,
+                                int byteOrder, int dataType) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiBricks cannot read datafiles");
+    Brick::writeBinaryGrid(in, filename, byteOrder, dataType);
+}
+
+void MultiBrick::dump(const string& fileName) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiBricks dump not implemented");
+    Brick::dump(fileName);
+}
+
+const dim_t* MultiBrick::borrowSampleReferenceIDs(int fsType) const
+{
+    switch (fsType) {
+        case Nodes:
+        case ReducedNodes: //FIXME: reduced
+            return &m_nodeId[0];
+        case DegreesOfFreedom:
+        case ReducedDegreesOfFreedom: //FIXME: reduced
+            return &m_dofId[0];
+        case Elements:
+        case ReducedElements:
+            return &m_elementId[0];
+        case FaceElements:
+        case ReducedFaceElements:
+            return &m_faceId[0];
+        case Points:
+            return &m_diracPointNodeIDs[0];
+        default:
+            break;
+    }
+
+    std::stringstream msg;
+    msg << "borrowSampleReferenceIDs: invalid function space type "<<fsType;
+    throw RipleyException(msg.str());
+}
+
+bool MultiBrick::ownSample(int fsType, index_t id) const
+{
+    if (getMPISize()==1)
+        return true;
+
+    switch (fsType) {
+        case Nodes:
+        case ReducedNodes: //FIXME: reduced
+            return (m_dofMap[id] < getNumDOF());
+        case DegreesOfFreedom:
+        case ReducedDegreesOfFreedom:
+            return true;
+        case Elements:
+        case ReducedElements:
+            {
+                // check ownership of element's _last_ node
+                const index_t x=id%m_NE[0] + 1;
+                const index_t y=id%(m_NE[0]*m_NE[1])/m_NE[0] + 1;
+                const index_t z=id/(m_NE[0]*m_NE[1]) + 1;
+                return (m_dofMap[x + m_NN[0]*y + m_NN[0]*m_NN[1]*z] < getNumDOF());
+            }
+        case FaceElements:
+        case ReducedFaceElements:
+            {
+                // check ownership of face element's last node
+                dim_t n=0;
+                for (size_t i=0; i<6; i++) {
+                    n+=m_faceCount[i];
+                    if (id<n) {
+                        const index_t j=id-n+m_faceCount[i];
+                        if (i>=4) { // front or back
+                            const index_t first=(i==4 ? 0 : m_NN[0]*m_NN[1]*(m_NN[2]-1));
+                            return (m_dofMap[first+j%m_NE[0]+1+(j/m_NE[0]+1)*m_NN[0]] < getNumDOF());
+                        } else if (i>=2) { // bottom or top
+                            const index_t first=(i==2 ? 0 : m_NN[0]*(m_NN[1]-1));
+                            return (m_dofMap[first+j%m_NE[0]+1+(j/m_NE[0]+1)*m_NN[0]*m_NN[1]] < getNumDOF());
+                        } else { // left or right
+                            const index_t first=(i==0 ? 0 : m_NN[0]-1);
+                            return (m_dofMap[first+(j%m_NE[1]+1)*m_NN[0]+(j/m_NE[1]+1)*m_NN[0]*m_NN[1]] < getNumDOF());
+                        }
+                    }
+                }
+                return false;
+            }
+        default:
+            break;
+    }
+
+    std::stringstream msg;
+    msg << "ownSample: invalid function space type " << fsType;
+    throw RipleyException(msg.str());
+}
+
+void MultiBrick::setToNormal(escript::Data& out) const
+{
+    const dim_t NE0 = m_NE[0];
+    const dim_t NE1 = m_NE[1];
+    const dim_t NE2 = m_NE[2];
+
+    if (out.getFunctionSpace().getTypeCode() == FaceElements) {
+        out.requireWrite();
+#pragma omp parallel
+        {
+            if (m_faceOffset[0] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k1 = 0; k1 < NE1; ++k1) {
+                        double* o = out.getSampleDataRW(m_faceOffset[0]+INDEX2(k1,k2,m_NE[1]));
+                        // set vector at four quadrature points
+                        *o++ = -1.; *o++ = 0.; *o++ = 0.;
+                        *o++ = -1.; *o++ = 0.; *o++ = 0.;
+                        *o++ = -1.; *o++ = 0.; *o++ = 0.;
+                        *o++ = -1.; *o++ = 0.; *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[1] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k1 = 0; k1 < NE1; ++k1) {
+                        double* o = out.getSampleDataRW(m_faceOffset[1]+INDEX2(k1,k2,m_NE[1]));
+                        // set vector at four quadrature points
+                        *o++ = 1.; *o++ = 0.; *o++ = 0.;
+                        *o++ = 1.; *o++ = 0.; *o++ = 0.;
+                        *o++ = 1.; *o++ = 0.; *o++ = 0.;
+                        *o++ = 1.; *o++ = 0.; *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[2] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[2]+INDEX2(k0,k2,m_NE[0]));
+                        // set vector at four quadrature points
+                        *o++ = 0.; *o++ = -1.; *o++ = 0.;
+                        *o++ = 0.; *o++ = -1.; *o++ = 0.;
+                        *o++ = 0.; *o++ = -1.; *o++ = 0.;
+                        *o++ = 0.; *o++ = -1.; *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[3] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[3]+INDEX2(k0,k2,m_NE[0]));
+                        // set vector at four quadrature points
+                        *o++ = 0.; *o++ = 1.; *o++ = 0.;
+                        *o++ = 0.; *o++ = 1.; *o++ = 0.;
+                        *o++ = 0.; *o++ = 1.; *o++ = 0.;
+                        *o++ = 0.; *o++ = 1.; *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[4] > -1) {
+#pragma omp for nowait
+                for (index_t k1 = 0; k1 < NE1; ++k1) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[4]+INDEX2(k0,k1,m_NE[0]));
+                        // set vector at four quadrature points
+                        *o++ = 0.; *o++ = 0.; *o++ = -1.;
+                        *o++ = 0.; *o++ = 0.; *o++ = -1.;
+                        *o++ = 0.; *o++ = 0.; *o++ = -1.;
+                        *o++ = 0.; *o++ = 0.; *o = -1.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[5] > -1) {
+#pragma omp for nowait
+                for (index_t k1 = 0; k1 < NE1; ++k1) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[5]+INDEX2(k0,k1,m_NE[0]));
+                        // set vector at four quadrature points
+                        *o++ = 0.; *o++ = 0.; *o++ = 1.;
+                        *o++ = 0.; *o++ = 0.; *o++ = 1.;
+                        *o++ = 0.; *o++ = 0.; *o++ = 1.;
+                        *o++ = 0.; *o++ = 0.; *o = 1.;
+                    }
+                }
+            }
+        } // end of parallel section
+    } else if (out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {
+        out.requireWrite();
+#pragma omp parallel
+        {
+            if (m_faceOffset[0] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k1 = 0; k1 < NE1; ++k1) {
+                        double* o = out.getSampleDataRW(m_faceOffset[0]+INDEX2(k1,k2,m_NE[1]));
+                        *o++ = -1.;
+                        *o++ = 0.;
+                        *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[1] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k1 = 0; k1 < NE1; ++k1) {
+                        double* o = out.getSampleDataRW(m_faceOffset[1]+INDEX2(k1,k2,m_NE[1]));
+                        *o++ = 1.;
+                        *o++ = 0.;
+                        *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[2] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[2]+INDEX2(k0,k2,m_NE[0]));
+                        *o++ = 0.;
+                        *o++ = -1.;
+                        *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[3] > -1) {
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[3]+INDEX2(k0,k2,m_NE[0]));
+                        *o++ = 0.;
+                        *o++ = 1.;
+                        *o = 0.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[4] > -1) {
+#pragma omp for nowait
+                for (index_t k1 = 0; k1 < NE1; ++k1) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[4]+INDEX2(k0,k1,m_NE[0]));
+                        *o++ = 0.;
+                        *o++ = 0.;
+                        *o = -1.;
+                    }
+                }
+            }
+
+            if (m_faceOffset[5] > -1) {
+#pragma omp for nowait
+                for (index_t k1 = 0; k1 < NE1; ++k1) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[5]+INDEX2(k0,k1,m_NE[0]));
+                        *o++ = 0.;
+                        *o++ = 0.;
+                        *o = 1.;
+                    }
+                }
+            }
+        } // end of parallel section
+
+    } else {
+        std::stringstream msg;
+        msg << "setToNormal: invalid function space type "
+            << out.getFunctionSpace().getTypeCode();
+        throw RipleyException(msg.str());
+    }
+}
+
+void MultiBrick::setToSize(escript::Data& out) const
+{
+    if (out.getFunctionSpace().getTypeCode() == Elements
+            || out.getFunctionSpace().getTypeCode() == ReducedElements) {
+        out.requireWrite();
+        const dim_t numQuad=out.getNumDataPointsPerSample();
+        const double size=sqrt(m_dx[0]*m_dx[0]+m_dx[1]*m_dx[1]+m_dx[2]*m_dx[2]);
+        const dim_t NE = getNumElements();
+#pragma omp parallel for
+        for (index_t k = 0; k < NE; ++k) {
+            double* o = out.getSampleDataRW(k);
+            fill(o, o+numQuad, size);
+        }
+    } else if (out.getFunctionSpace().getTypeCode() == FaceElements
+            || out.getFunctionSpace().getTypeCode() == ReducedFaceElements) {
+        out.requireWrite();
+        const dim_t numQuad=out.getNumDataPointsPerSample();
+        const dim_t NE0 = m_NE[0];
+        const dim_t NE1 = m_NE[1];
+        const dim_t NE2 = m_NE[2];
+#pragma omp parallel
+        {
+            if (m_faceOffset[0] > -1) {
+                const double size=min(m_dx[1],m_dx[2]);
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k1 = 0; k1 < NE1; ++k1) {
+                        double* o = out.getSampleDataRW(m_faceOffset[0]+INDEX2(k1,k2,m_NE[1]));
+                        fill(o, o+numQuad, size);
+                    }
+                }
+            }
+
+            if (m_faceOffset[1] > -1) {
+                const double size=min(m_dx[1],m_dx[2]);
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k1 = 0; k1 < NE1; ++k1) {
+                        double* o = out.getSampleDataRW(m_faceOffset[1]+INDEX2(k1,k2,m_NE[1]));
+                        fill(o, o+numQuad, size);
+                    }
+                }
+            }
+
+            if (m_faceOffset[2] > -1) {
+                const double size=min(m_dx[0],m_dx[2]);
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[2]+INDEX2(k0,k2,m_NE[0]));
+                        fill(o, o+numQuad, size);
+                    }
+                }
+            }
+
+            if (m_faceOffset[3] > -1) {
+                const double size=min(m_dx[0],m_dx[2]);
+#pragma omp for nowait
+                for (index_t k2 = 0; k2 < NE2; ++k2) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[3]+INDEX2(k0,k2,m_NE[0]));
+                        fill(o, o+numQuad, size);
+                    }
+                }
+            }
+
+            if (m_faceOffset[4] > -1) {
+                const double size=min(m_dx[0],m_dx[1]);
+#pragma omp for nowait
+                for (index_t k1 = 0; k1 < NE1; ++k1) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[4]+INDEX2(k0,k1,m_NE[0]));
+                        fill(o, o+numQuad, size);
+                    }
+                }
+            }
+
+            if (m_faceOffset[5] > -1) {
+                const double size=min(m_dx[0],m_dx[1]);
+#pragma omp for nowait
+                for (index_t k1 = 0; k1 < NE1; ++k1) {
+                    for (index_t k0 = 0; k0 < NE0; ++k0) {
+                        double* o = out.getSampleDataRW(m_faceOffset[5]+INDEX2(k0,k1,m_NE[0]));
+                        fill(o, o+numQuad, size);
+                    }
+                }
+            }
+        } // end of parallel section
+
+    } else {
+        std::stringstream msg;
+        msg << "setToSize: invalid function space type "
+            << out.getFunctionSpace().getTypeCode();
+        throw RipleyException(msg.str());
+    }
+}
+
+void MultiBrick::Print_Mesh_Info(const bool full) const
+{
+    RipleyDomain::Print_Mesh_Info(full);
+    if (full) {
+        std::cout << "     Id  Coordinates" << std::endl;
+        std::cout.precision(15);
+        std::cout.setf(ios::scientific, std::ios::floatfield);
+        for (index_t i=0; i < getNumNodes(); i++) {
+            std::cout << "  " << std::setw(5) << m_nodeId[i]
+                << "  " << getLocalCoordinate(i%m_NN[0], 0)
+                << "  " << getLocalCoordinate(i%(m_NN[0]*m_NN[1])/m_NN[0], 1)
+                << "  " << getLocalCoordinate(i/(m_NN[0]*m_NN[1]), 2) << std::endl;
+        }
+    }
+}
+
+//protected
+IndexVector MultiBrick::getDiagonalIndices(bool upperOnly) const
+{
+    IndexVector ret;
+    // only store non-negative indices if requested
+    if (upperOnly)
+        ret.resize(14);
+    else
+        ret.resize(27);
+
+    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
+    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    size_t idx = 0;
+    for (int i2=-1; i2<2; i2++) {
+        for (int i1=-1; i1<2; i1++) {
+            for (int i0=-1; i0<2; i0++) {
+                const int index = i2*nDOF0*nDOF1 + i1*nDOF0 + i0;
+                if (!upperOnly || index >= 0)
+                    ret[idx++] = index;
+            }
+        }
+    }
+
+    return ret;
+}
+
+//private
+void MultiBrick::populateSampleIds()
+{
+    // degrees of freedom are numbered from left to right, bottom to top, front
+    // to back in each rank, continuing on the next rank (ranks also go
+    // left-right, bottom-top, front-back).
+    // This means rank 0 has id 0...n0-1, rank 1 has id n0...n1-1 etc. which
+    // helps when writing out data rank after rank.
+
+    // build node distribution vector first.
+    // rank i owns m_nodeDistribution[i+1]-nodeDistribution[i] nodes which is
+    // constant for all ranks in this implementation
+    m_nodeDistribution.assign(m_mpiInfo->size+1, 0);
+    const dim_t numDOF=getNumDOF();
+    for (dim_t k=1; k<m_mpiInfo->size; k++) {
+        m_nodeDistribution[k]=k*numDOF;
+    }
+    m_nodeDistribution[m_mpiInfo->size]=getNumDataPointsGlobal();
+
+    try {
+        m_nodeId.resize(getNumNodes());
+        m_dofId.resize(numDOF);
+        m_elementId.resize(getNumElements());
+    } catch (const std::length_error& le) {
+        throw RipleyException("The system does not have sufficient memory for a domain of this size.");
+    }
+
+    // populate face element counts
+    //left
+    if (m_offset[0]==0)
+        m_faceCount[0]=m_NE[1]*m_NE[2];
+    else
+        m_faceCount[0]=0;
+    //right
+    if (m_mpiInfo->rank%m_NX[0]==m_NX[0]-1)
+        m_faceCount[1]=m_NE[1]*m_NE[2];
+    else
+        m_faceCount[1]=0;
+    //bottom
+    if (m_offset[1]==0)
+        m_faceCount[2]=m_NE[0]*m_NE[2];
+    else
+        m_faceCount[2]=0;
+    //top
+    if (m_mpiInfo->rank%(m_NX[0]*m_NX[1])/m_NX[0]==m_NX[1]-1)
+        m_faceCount[3]=m_NE[0]*m_NE[2];
+    else
+        m_faceCount[3]=0;
+    //front
+    if (m_offset[2]==0)
+        m_faceCount[4]=m_NE[0]*m_NE[1];
+    else
+        m_faceCount[4]=0;
+    //back
+    if (m_mpiInfo->rank/(m_NX[0]*m_NX[1])==m_NX[2]-1)
+        m_faceCount[5]=m_NE[0]*m_NE[1];
+    else
+        m_faceCount[5]=0;
+
+    const dim_t NFE = getNumFaceElements();
+    m_faceId.resize(NFE);
+
+    const index_t left = (m_offset[0]==0 ? 0 : 1);
+    const index_t bottom = (m_offset[1]==0 ? 0 : 1);
+    const index_t front = (m_offset[2]==0 ? 0 : 1);
+    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
+    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    const dim_t nDOF2 = (m_gNE[2]+1)/m_NX[2];
+    const dim_t NN0 = m_NN[0];
+    const dim_t NN1 = m_NN[1];
+    const dim_t NN2 = m_NN[2];
+    const dim_t NE0 = m_NE[0];
+    const dim_t NE1 = m_NE[1];
+    const dim_t NE2 = m_NE[2];
+
+    // the following is a compromise between efficiency and code length to
+    // set the node id's according to the order mentioned above.
+    // First we set all the edge and corner id's in a rather slow way since
+    // they might or might not be owned by this rank. Next come the own
+    // node id's which are identical to the DOF id's (simple loop), and finally
+    // the 6 faces are set but only if required...
+
+#define globalNodeId(x,y,z) \
+    ((m_offset[0]+x)/nDOF0)*nDOF0*nDOF1*nDOF2+(m_offset[0]+x)%nDOF0\
+    + ((m_offset[1]+y)/nDOF1)*nDOF0*nDOF1*nDOF2*m_NX[0]+((m_offset[1]+y)%nDOF1)*nDOF0\
+    + ((m_offset[2]+z)/nDOF2)*nDOF0*nDOF1*nDOF2*m_NX[0]*m_NX[1]+((m_offset[2]+z)%nDOF2)*nDOF0*nDOF1
+
+#pragma omp parallel
+    {
+        // set edge id's
+        // edges in x-direction, including corners
+#pragma omp for nowait
+        for (dim_t i=0; i<NN0; i++) {
+            m_nodeId[i] = globalNodeId(i, 0, 0); // LF
+            m_nodeId[NN0*(NN1-1)+i] = globalNodeId(i, NN1-1, 0); // UF
+            m_nodeId[NN0*NN1*(NN2-1)+i] = globalNodeId(i, 0, NN2-1); // LB
+            m_nodeId[NN0*NN1*NN2-NN0+i] = globalNodeId(i, NN1-1, NN2-1); // UB
+        }
+        // edges in y-direction, without corners
+#pragma omp for nowait
+        for (dim_t i=1; i<NN1-1; i++) {
+            m_nodeId[NN0*i] = globalNodeId(0, i, 0); // FL
+            m_nodeId[NN0*(i+1)-1] = globalNodeId(NN0-1, i, 0); // FR
+            m_nodeId[NN0*NN1*(NN2-1)+NN0*i] = globalNodeId(0, i, NN2-1); // BL
+            m_nodeId[NN0*NN1*(NN2-1)+NN0*(i+1)-1] = globalNodeId(NN0-1, i, NN2-1); // BR
+        }
+        // edges in z-direction, without corners
+#pragma omp for
+        for (dim_t i=1; i<NN2-1; i++) {
+            m_nodeId[NN0*NN1*i] = globalNodeId(0, 0, i); // LL
+            m_nodeId[NN0*NN1*i+NN0-1] = globalNodeId(NN0-1, 0, i); // LR
+            m_nodeId[NN0*NN1*(i+1)-NN0] = globalNodeId(0, NN1-1, i); // UL
+            m_nodeId[NN0*NN1*(i+1)-1] = globalNodeId(NN0-1, NN1-1, i); // UR
+        }
+        // implicit barrier here because some node IDs will be overwritten
+        // below
+
+        // populate degrees of freedom and own nodes (identical id)
+#pragma omp for nowait
+        for (dim_t i=0; i<nDOF2; i++) {
+            for (dim_t j=0; j<nDOF1; j++) {
+                for (dim_t k=0; k<nDOF0; k++) {
+                    const index_t nodeIdx=k+left+(j+bottom)*NN0+(i+front)*NN0*NN1;
+                    const index_t dofIdx=k+j*nDOF0+i*nDOF0*nDOF1;
+                    m_dofId[dofIdx] = m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank]+dofIdx;
+                }
+            }
+        }
+
+        // populate the rest of the nodes (shared with other ranks)
+        if (m_faceCount[0]==0) { // left plane
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF2; i++) {
+                for (dim_t j=0; j<nDOF1; j++) {
+                    const index_t nodeIdx=(j+bottom)*NN0+(i+front)*NN0*NN1;
+                    const index_t dofId=(j+1)*nDOF0-1+i*nDOF0*nDOF1;
+                    m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank-1]+dofId;
+                }
+            }
+        }
+        if (m_faceCount[1]==0) { // right plane
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF2; i++) {
+                for (dim_t j=0; j<nDOF1; j++) {
+                    const index_t nodeIdx=(j+bottom+1)*NN0-1+(i+front)*NN0*NN1;
+                    const index_t dofId=j*nDOF0+i*nDOF0*nDOF1;
+                    m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank+1]+dofId;
+                }
+            }
+        }
+        if (m_faceCount[2]==0) { // bottom plane
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF2; i++) {
+                for (dim_t k=0; k<nDOF0; k++) {
+                    const index_t nodeIdx=k+left+(i+front)*NN0*NN1;
+                    const index_t dofId=nDOF0*(nDOF1-1)+k+i*nDOF0*nDOF1;
+                    m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank-m_NX[0]]+dofId;
+                }
+            }
+        }
+        if (m_faceCount[3]==0) { // top plane
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF2; i++) {
+                for (dim_t k=0; k<nDOF0; k++) {
+                    const index_t nodeIdx=k+left+(i+front)*NN0*NN1+NN0*(NN1-1);
+                    const index_t dofId=k+i*nDOF0*nDOF1;
+                    m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank+m_NX[0]]+dofId;
+                }
+            }
+        }
+        if (m_faceCount[4]==0) { // front plane
+#pragma omp for nowait
+            for (dim_t j=0; j<nDOF1; j++) {
+                for (dim_t k=0; k<nDOF0; k++) {
+                    const index_t nodeIdx=k+left+(j+bottom)*NN0;
+                    const index_t dofId=k+j*nDOF0+nDOF0*nDOF1*(nDOF2-1);
+                    m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank-m_NX[0]*m_NX[1]]+dofId;
+                }
+            }
+        }
+        if (m_faceCount[5]==0) { // back plane
+#pragma omp for nowait
+            for (dim_t j=0; j<nDOF1; j++) {
+                for (dim_t k=0; k<nDOF0; k++) {
+                    const index_t nodeIdx=k+left+(j+bottom)*NN0+NN0*NN1*(NN2-1);
+                    const index_t dofId=k+j*nDOF0;
+                    m_nodeId[nodeIdx]
+                        = m_nodeDistribution[m_mpiInfo->rank+m_NX[0]*m_NX[1]]+dofId;
+                }
+            }
+        }
+
+        // populate element id's
+#pragma omp for nowait
+        for (dim_t i2=0; i2<NE2; i2++) {
+            for (dim_t i1=0; i1<NE1; i1++) {
+                for (dim_t i0=0; i0<NE0; i0++) {
+                    m_elementId[i0+i1*NE0+i2*NE0*NE1] =
+                        (m_offset[2]+i2)*m_gNE[0]*m_gNE[1]
+                        +(m_offset[1]+i1)*m_gNE[0]
+                        +m_offset[0]+i0;
+                }
+            }
+        }
+
+        // face elements
+#pragma omp for
+        for (dim_t k=0; k<NFE; k++)
+            m_faceId[k]=k;
+    } // end parallel section
+
+#undef globalNodeId
+
+    m_nodeTags.assign(getNumNodes(), 0);
+    updateTagsInUse(Nodes);
+
+    m_elementTags.assign(getNumElements(), 0);
+    updateTagsInUse(Elements);
+
+    // generate face offset vector and set face tags
+    const index_t LEFT=1, RIGHT=2, BOTTOM=10, TOP=20, FRONT=100, BACK=200;
+    const index_t faceTag[] = { LEFT, RIGHT, BOTTOM, TOP, FRONT, BACK };
+    m_faceOffset.assign(6, -1);
+    m_faceTags.clear();
+    index_t offset=0;
+    for (size_t i=0; i<6; i++) {
+        if (m_faceCount[i]>0) {
+            m_faceOffset[i]=offset;
+            offset+=m_faceCount[i];
+            m_faceTags.insert(m_faceTags.end(), m_faceCount[i], faceTag[i]);
+        }
+    }
+    setTagMap("left", LEFT);
+    setTagMap("right", RIGHT);
+    setTagMap("bottom", BOTTOM);
+    setTagMap("top", TOP);
+    setTagMap("front", FRONT);
+    setTagMap("back", BACK);
+    updateTagsInUse(FaceElements);
+
+    populateDofMap();
+}
+
+//private
+vector<IndexVector> MultiBrick::getConnections() const
+{
+    // returns a vector v of size numDOF where v[i] is a vector with indices
+    // of DOFs connected to i (up to 27 in 3D)
+    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
+    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    const dim_t nDOF2 = (m_gNE[2]+1)/m_NX[2];
+    const dim_t M = nDOF0*nDOF1*nDOF2;
+    vector<IndexVector> indices(M);
+
+#pragma omp parallel for
+    for (index_t i=0; i < M; i++) {
+        const index_t x = i % nDOF0;
+        const index_t y = i % (nDOF0*nDOF1)/nDOF0;
+        const index_t z = i / (nDOF0*nDOF1);
+        // loop through potential neighbours and add to index if positions are
+        // within bounds
+        for (int i2=z-1; i2<z+2; i2++) {
+            for (int i1=y-1; i1<y+2; i1++) {
+                for (int i0=x-1; i0<x+2; i0++) {
+                    if (i0>=0 && i1>=0 && i2>=0
+                            && i0<nDOF0 && i1<nDOF1 && i2<nDOF2) {
+                        indices[i].push_back(i2*nDOF0*nDOF1 + i1*nDOF0 + i0);
+                    }
+                }
+            }
+        }
+    }
+    return indices;
+}
+
+//private
+void MultiBrick::populateDofMap()
+{
+    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
+    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    const dim_t nDOF2 = (m_gNE[2]+1)/m_NX[2];
+    const index_t left = (m_offset[0]==0 ? 0 : 1);
+    const index_t bottom = (m_offset[1]==0 ? 0 : 1);
+    const index_t front = (m_offset[2]==0 ? 0 : 1);
+
+    // populate node->DOF mapping with own degrees of freedom.
+    // The rest is assigned in the loop further down
+    m_dofMap.assign(getNumNodes(), 0);
+#pragma omp parallel for
+    for (index_t i=front; i<front+nDOF2; i++) {
+        for (index_t j=bottom; j<bottom+nDOF1; j++) {
+            for (index_t k=left; k<left+nDOF0; k++) {
+                m_dofMap[i*m_NN[0]*m_NN[1]+j*m_NN[0]+k]=(i-front)*nDOF0*nDOF1+(j-bottom)*nDOF0+k-left;
+            }
+        }
+    }
+
+    const dim_t numDOF=nDOF0*nDOF1*nDOF2;
+    RankVector neighbour;
+    IndexVector offsetInShared(1,0);
+    IndexVector sendShared, recvShared;
+    dim_t numShared=0;
+    const int x=m_mpiInfo->rank%m_NX[0];
+    const int y=m_mpiInfo->rank%(m_NX[0]*m_NX[1])/m_NX[0];
+    const int z=m_mpiInfo->rank/(m_NX[0]*m_NX[1]);
+
+    // build list of shared components and neighbours by looping through
+    // all potential neighbouring ranks and checking if positions are
+    // within bounds
+    for (int i2=-1; i2<2; i2++) {
+        for (int i1=-1; i1<2; i1++) {
+            for (int i0=-1; i0<2; i0++) {
+                // skip this rank
+                if (i0==0 && i1==0 && i2==0)
+                    continue;
+                // location of neighbour rank
+                const int nx=x+i0;
+                const int ny=y+i1;
+                const int nz=z+i2;
+                if (nx>=0 && ny>=0 && nz>=0 && nx<m_NX[0] && ny<m_NX[1] && nz<m_NX[2]) {
+                    neighbour.push_back(nz*m_NX[0]*m_NX[1]+ny*m_NX[0]+nx);
+                    if (i0==0 && i1==0) {
+                        // sharing front or back plane
+                        offsetInShared.push_back(offsetInShared.back()+nDOF0*nDOF1);
+                        for (dim_t i=0; i<nDOF1; i++) {
+                            const dim_t firstDOF=(i2==-1 ? i*nDOF0
+                                    : i*nDOF0 + nDOF0*nDOF1*(nDOF2-1));
+                            const dim_t firstNode=(i2==-1 ? left+(i+bottom)*m_NN[0]
+                                    : left+(i+bottom)*m_NN[0]+m_NN[0]*m_NN[1]*(m_NN[2]-1));
+                            for (dim_t j=0; j<nDOF0; j++, numShared++) {
+                                sendShared.push_back(firstDOF+j);
+                                recvShared.push_back(numDOF+numShared);
+                                m_dofMap[firstNode+j]=numDOF+numShared;
+                            }
+                        }
+                    } else if (i0==0 && i2==0) {
+                        // sharing top or bottom plane
+                        offsetInShared.push_back(offsetInShared.back()+nDOF0*nDOF2);
+                        for (dim_t i=0; i<nDOF2; i++) {
+                            const dim_t firstDOF=(i1==-1 ? i*nDOF0*nDOF1
+                                    : nDOF0*((i+1)*nDOF1-1));
+                            const dim_t firstNode=(i1==-1 ?
+                                    left+(i+front)*m_NN[0]*m_NN[1]
+                                    : left+m_NN[0]*((i+1+front)*m_NN[1]-1));
+                            for (dim_t j=0; j<nDOF0; j++, numShared++) {
+                                sendShared.push_back(firstDOF+j);
+                                recvShared.push_back(numDOF+numShared);
+                                m_dofMap[firstNode+j]=numDOF+numShared;
+                            }
+                        }
+                    } else if (i1==0 && i2==0) {
+                        // sharing left or right plane
+                        offsetInShared.push_back(offsetInShared.back()+nDOF1*nDOF2);
+                        for (dim_t i=0; i<nDOF2; i++) {
+                            const dim_t firstDOF=(i0==-1 ? i*nDOF0*nDOF1
+                                    : nDOF0*(1+i*nDOF1)-1);
+                            const dim_t firstNode=(i0==-1 ?
+                                    (bottom+(i+front)*m_NN[1])*m_NN[0]
+                                    : (bottom+1+(i+front)*m_NN[1])*m_NN[0]-1);
+                            for (dim_t j=0; j<nDOF1; j++, numShared++) {
+                                sendShared.push_back(firstDOF+j*nDOF0);
+                                recvShared.push_back(numDOF+numShared);
+                                m_dofMap[firstNode+j*m_NN[0]]=numDOF+numShared;
+                            }
+                        }
+                    } else if (i0==0) {
+                        // sharing an edge in x direction
+                        offsetInShared.push_back(offsetInShared.back()+nDOF0);
+                        const dim_t firstDOF=(i1+1)/2*nDOF0*(nDOF1-1)
+                                           +(i2+1)/2*nDOF0*nDOF1*(nDOF2-1);
+                        const dim_t firstNode=left+(i1+1)/2*m_NN[0]*(m_NN[1]-1)
+                                            +(i2+1)/2*m_NN[0]*m_NN[1]*(m_NN[2]-1);
+                        for (dim_t i=0; i<nDOF0; i++, numShared++) {
+                            sendShared.push_back(firstDOF+i);
+                            recvShared.push_back(numDOF+numShared);
+                            m_dofMap[firstNode+i]=numDOF+numShared;
+                        }
+                    } else if (i1==0) {
+                        // sharing an edge in y direction
+                        offsetInShared.push_back(offsetInShared.back()+nDOF1);
+                        const dim_t firstDOF=(i0+1)/2*(nDOF0-1)
+                                           +(i2+1)/2*nDOF0*nDOF1*(nDOF2-1);
+                        const dim_t firstNode=bottom*m_NN[0]
+                                            +(i0+1)/2*(m_NN[0]-1)
+                                            +(i2+1)/2*m_NN[0]*m_NN[1]*(m_NN[2]-1);
+                        for (dim_t i=0; i<nDOF1; i++, numShared++) {
+                            sendShared.push_back(firstDOF+i*nDOF0);
+                            recvShared.push_back(numDOF+numShared);
+                            m_dofMap[firstNode+i*m_NN[0]]=numDOF+numShared;
+                        }
+                    } else if (i2==0) {
+                        // sharing an edge in z direction
+                        offsetInShared.push_back(offsetInShared.back()+nDOF2);
+                        const dim_t firstDOF=(i0+1)/2*(nDOF0-1)
+                                           +(i1+1)/2*nDOF0*(nDOF1-1);
+                        const dim_t firstNode=front*m_NN[0]*m_NN[1]
+                                            +(i0+1)/2*(m_NN[0]-1)
+                                            +(i1+1)/2*m_NN[0]*(m_NN[1]-1);
+                        for (dim_t i=0; i<nDOF2; i++, numShared++) {
+                            sendShared.push_back(firstDOF+i*nDOF0*nDOF1);
+                            recvShared.push_back(numDOF+numShared);
+                            m_dofMap[firstNode+i*m_NN[0]*m_NN[1]]=numDOF+numShared;
+                        }
+                    } else {
+                        // sharing a node
+                        const dim_t dof = (i0+1)/2*(nDOF0-1)
+                                       +(i1+1)/2*nDOF0*(nDOF1-1)
+                                       +(i2+1)/2*nDOF0*nDOF1*(nDOF2-1);
+                        const dim_t node = (i0+1)/2*(m_NN[0]-1)
+                                        +(i1+1)/2*m_NN[0]*(m_NN[1]-1)
+                                        +(i2+1)/2*m_NN[0]*m_NN[1]*(m_NN[2]-1);
+                        offsetInShared.push_back(offsetInShared.back()+1);
+                        sendShared.push_back(dof);
+                        recvShared.push_back(numDOF+numShared);
+                        m_dofMap[node] = numDOF+numShared;
+                        ++numShared;
+                    }
+                }
+            }
+        }
+    }
+
+    // TODO: paso::SharedComponents should take vectors to avoid this
+    Esys_MPI_rank* neighPtr = NULL;
+    index_t* sendPtr = NULL;
+    index_t* recvPtr = NULL;
+    if (neighbour.size() > 0) {
+        neighPtr = &neighbour[0];
+        sendPtr = &sendShared[0];
+        recvPtr = &recvShared[0];
+    }
+    // create connector
+    paso::SharedComponents_ptr snd_shcomp(new paso::SharedComponents(
+            numDOF, neighbour.size(), neighPtr, sendPtr,
+            &offsetInShared[0], 1, 0, m_mpiInfo));
+    paso::SharedComponents_ptr rcv_shcomp(new paso::SharedComponents(
+            numDOF, neighbour.size(), neighPtr, recvPtr,
+            &offsetInShared[0], 1, 0, m_mpiInfo));
+    m_connector.reset(new paso::Connector(snd_shcomp, rcv_shcomp));
+
+    // useful debug output
+    /*
+    std::cout << "--- rcv_shcomp ---" << std::endl;
+    std::cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << std::endl;
+    for (size_t i=0; i<neighbour.size(); i++) {
+        std::cout << "neighbor[" << i << "]=" << neighbour[i]
+            << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << std::endl;
+    }
+    for (size_t i=0; i<recvShared.size(); i++) {
+        std::cout << "shared[" << i << "]=" << recvShared[i] << std::endl;
+    }
+    std::cout << "--- snd_shcomp ---" << std::endl;
+    for (size_t i=0; i<sendShared.size(); i++) {
+        std::cout << "shared[" << i << "]=" << sendShared[i] << std::endl;
+    }
+    std::cout << "--- dofMap ---" << std::endl;
+    for (size_t i=0; i<m_dofMap.size(); i++) {
+        std::cout << "m_dofMap[" << i << "]=" << m_dofMap[i] << std::endl;
+    }
+    */
+}
+
+RankVector MultiBrick::getOwnerVector(int fsType) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Multiresolution domains only support ownership for the coarsest level");
+    return Brick::getOwnerVector(fsType);
+}
+
+dim_t MultiBrick::findNode(const double *coords) const
+{
+    const dim_t NOT_MINE = -1;
+    //is the found element even owned by this rank
+    // (inside owned or shared elements but will map to an owned element)
+    for (int dim = 0; dim < m_numDim; dim++) {
+        double min = m_origin[dim] + m_offset[dim]* m_dx[dim]
+                - m_dx[dim]/2.; //allows for point outside mapping onto node
+        double max = m_origin[dim] + (m_offset[dim] + m_NE[dim])*m_dx[dim]
+                + m_dx[dim]/2.;
+        if (min > coords[dim] || max < coords[dim]) {
+            return NOT_MINE;
+        }
+    }
+    // get distance from origin
+    double x = coords[0] - m_origin[0];
+    double y = coords[1] - m_origin[1];
+    double z = coords[2] - m_origin[2];
+
+    //check if the point is even inside the domain
+    if (x < 0 || y < 0 || z < 0
+            || x > m_length[0] || y > m_length[1] || z > m_length[2])
+        return NOT_MINE;
+
+    // distance in elements
+    dim_t ex = (dim_t) floor(x / m_dx[0]);
+    dim_t ey = (dim_t) floor(y / m_dx[1]);
+    dim_t ez = (dim_t) floor(z / m_dx[2]);
+    // set the min distance high enough to be outside the element plus a bit
+    dim_t closest = NOT_MINE;
+    double minDist = 1;
+    for (int dim = 0; dim < m_numDim; dim++) {
+        minDist += m_dx[dim]*m_dx[dim];
+    }
+    //find the closest node
+    for (int dx = 0; dx < 1; dx++) {
+        double xdist = x - (ex + dx)*m_dx[0];
+        for (int dy = 0; dy < 1; dy++) {
+            double ydist = y - (ey + dy)*m_dx[1];
+            for (int dz = 0; dz < 1; dz++) {
+                double zdist = z - (ez + dz)*m_dx[2];
+                double total = xdist*xdist + ydist*ydist + zdist*zdist;
+                if (total < minDist) {
+                    closest = INDEX3(ex+dy-m_offset[0], ey+dy-m_offset[1],
+                            ez+dz-m_offset[2], m_NE[0]+1, m_NE[1]+1);
+                    minDist = total;
+                }
+            }
+        }
+    }
+    if (closest == NOT_MINE) {
+        throw RipleyException("Unable to map appropriate dirac point to a "
+                         "node, implementation problem in MultiBrick::findNode()");
+    }
+    return closest;
+}
+
+} // end of namespace ripley
+
diff --git a/ripley/src/MultiBrick.h b/ripley/src/MultiBrick.h
new file mode 100644
index 0000000..314a304
--- /dev/null
+++ b/ripley/src/MultiBrick.h
@@ -0,0 +1,204 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#ifndef __RIPLEY_MULTIBRICK_H__
+#define __RIPLEY_MULTIBRICK_H__
+
+#include <ripley/Brick.h>
+
+namespace ripley {
+
+/**
+   \brief
+   Brick is the 3-dimensional implementation of a RipleyDomain.
+*/
+class RIPLEY_DLL_API MultiBrick: public Brick
+{
+    friend class DefaultAssembler3D;
+    friend class WaveAssembler3D;
+    friend class LameAssembler3D;
+public:
+
+    /**
+       \brief creates a hexagonal mesh with n0 x n1 x n2 elements over the
+              brick [x0,x1] x [y0,y1] x [z0,z1].
+       \param n0,n1,n2 number of elements in each dimension
+       \param x0,y0,z0,x1,y1,z1 coordinates of corner nodes of the brick
+       \param d0,d1,d2 number of subdivisions in each dimension
+    */
+    MultiBrick(dim_t n0, dim_t n1, dim_t n2, double x0, double y0, double z0,
+          double x1, double y1, double z1, int d0=-1, int d1=-1, int d2=-1,
+          const std::vector<double>& points = std::vector<double>(),
+          const std::vector<int>& tags = std::vector<int>(),
+          const TagMap& tagnamestonums = TagMap(),
+          escript::SubWorld_ptr w=escript::SubWorld_ptr(),
+              unsigned int subdivisions = 1
+ 	    );
+
+    /**
+       \brief
+       Destructor.
+    */
+    ~MultiBrick();
+
+    /**
+       \brief
+       interpolates data given on source onto target where source and target
+       are given on different domains
+    */
+    virtual void interpolateAcross(escript::Data& target,
+                                   const escript::Data& source) const;
+
+    /**
+       \brief
+       Checks that the given interpolation is possible, throw RipleyExceptions
+       if not
+    */
+    void validateInterpolationAcross(int fsType_source,
+              const escript::AbstractDomain& domain, int fsType_target) const;
+    
+    /**
+       \brief
+       returns a description for this domain
+    */
+    virtual std::string getDescription() const;
+
+    /**
+       \brief equality operator
+    */
+    virtual bool operator==(const escript::AbstractDomain& other) const;
+
+    /**
+       \brief
+       dumps the mesh to a file with the given name
+       \param filename The name of the output file
+    */
+    void dump(const std::string& filename) const;
+
+    /**
+    */
+    virtual void readNcGrid(escript::Data& out, std::string filename,
+            std::string varname, const ReaderParameters& params) const;
+
+    /**
+    */
+    virtual void readBinaryGrid(escript::Data& out, std::string filename,
+                                const ReaderParameters& params) const;
+
+#ifdef USE_BOOSTIO
+    virtual void readBinaryGridFromZipped(escript::Data& out, std::string filename,
+                                const ReaderParameters& params) const;
+#endif
+
+    /**
+    */
+    virtual void writeBinaryGrid(const escript::Data& in,
+                                 std::string filename,
+                                 int byteOrder, int dataType) const;
+    /**
+       \brief
+       returns the array of reference numbers for a function space type
+       \param fsType The function space type
+    */
+    const dim_t* borrowSampleReferenceIDs(int fsType) const;
+
+    /**
+       \brief
+       returns true if this rank owns the sample id.
+    */
+    virtual bool ownSample(int fsType, index_t id) const;
+
+    /**
+       \brief
+       copies the surface normals at data points into out. The actual function
+       space to be considered is defined by out. out has to be defined on this
+       domain.
+    */
+    virtual void setToNormal(escript::Data& out) const;
+
+    /**
+       \brief
+       copies the size of samples into out. The actual function space to be
+       considered is defined by out. out has to be defined on this domain.
+    */
+    virtual void setToSize(escript::Data& out) const;
+
+    /**
+       \brief
+       writes information about the mesh to standard output
+       \param full whether to print additional data
+    */
+    virtual void Print_Mesh_Info(const bool full=false) const;
+
+    /**
+       \brief
+       returns the number of times each root element has been subdivided
+    */
+    virtual unsigned int getNumSubdivisionsPerElement() const { return m_subdivisions; }
+
+    /**
+       \brief
+       returns the number of face elements in the order
+       (left,right,bottom,top,front,back) on current MPI rank
+    */
+    virtual const dim_t* getNumFacesPerBoundary() const { return m_faceCount; }
+
+    /**
+       \brief
+       returns the node distribution vector
+    */
+    virtual IndexVector getNodeDistribution() const { return m_nodeDistribution; }
+
+    /**
+       \brief
+       returns the number of spatial subdivisions in each dimension
+    */
+    virtual const int* getNumSubdivisionsPerDim() const { return m_NX; }
+
+    /**
+       \brief
+       returns a vector of rank numbers where vec[i]=n means that rank n
+       'owns' element/face element i.
+    */
+    virtual RankVector getOwnerVector(int fsType) const;
+
+protected:
+    virtual IndexVector getDiagonalIndices(bool upperOnly) const;
+    virtual void interpolateNodesToNodesFiner(const escript::Data& source, escript::Data& target, const MultiBrick& other) const;
+    virtual void interpolateNodesToElementsFiner(const escript::Data& source, escript::Data& target, const MultiBrick& other) const;
+
+    virtual void interpolateElementsToElementsCoarser(const escript::Data& source, escript::Data& target, const MultiBrick& other) const;
+    virtual void interpolateElementsToElementsFiner(const escript::Data& source, escript::Data& target, const MultiBrick& other) const;
+
+    virtual void interpolateReducedToElementsFiner(const escript::Data& source, escript::Data& target, const MultiBrick& other) const;
+    virtual void interpolateReducedToReducedFiner(const escript::Data& source, escript::Data& target, const MultiBrick& other) const;
+
+    void populateSampleIds();
+    void populateDofMap();
+    std::vector<IndexVector> getConnections() const;
+
+    dim_t findNode(const double *coords) const;
+
+    const unsigned int m_subdivisions;
+};
+
+
+
+
+} // end of namespace ripley
+
+#endif // __RIPLEY_MULTIBRICK_H__
+
diff --git a/ripley/src/MultiRectangle.cpp b/ripley/src/MultiRectangle.cpp
new file mode 100644
index 0000000..226e3fe
--- /dev/null
+++ b/ripley/src/MultiRectangle.cpp
@@ -0,0 +1,963 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+#include <ripley/MultiRectangle.h>
+#include <ripley/blocktools.h>
+#include <ripley/domainhelpers.h>
+#include <paso/SystemMatrix.h>
+#include <esysUtils/esysFileWriter.h>
+#include <esysUtils/EsysRandom.h>
+#include <escript/DataFactory.h>
+#include <escript/FunctionSpaceFactory.h>
+#include <boost/scoped_array.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>	// for isnan
+
+#ifdef USE_NETCDF
+#include <netcdfcpp.h>
+#endif
+
+#if USE_SILO
+#include <silo.h>
+#ifdef ESYS_MPI
+#include <pmpio.h>
+#endif
+#endif
+
+#define FIRST_QUAD 0.21132486540518711775
+#define SECOND_QUAD 0.78867513459481288225
+
+#include <iomanip>
+#include <limits>
+
+
+#include <algorithm>
+
+namespace bp = boost::python;
+using esysUtils::FileWriter;
+using escript::AbstractSystemMatrix;
+
+using std::vector;
+using std::string;
+using std::min;
+using std::max;
+using std::copy;
+using std::ios;
+using std::fill;
+
+namespace ripley {
+
+MultiRectangle::MultiRectangle(dim_t n0, dim_t n1, double x0, double y0,
+                     double x1, double y1, int d0, int d1,
+                     const vector<double>& points,
+                     const vector<int>& tags,
+                     const TagMap& tagnamestonums,
+                     escript::SubWorld_ptr w, unsigned int subdivisions)
+     : Rectangle(n0,n1, x0,y0, x1,y1, d0,d1, points, tags, tagnamestonums, w),
+       m_subdivisions(subdivisions)
+{
+    if (subdivisions == 0 || (subdivisions & (subdivisions - 1)) != 0)
+        throw RipleyException("Element subdivisions must be a power of two");
+
+    dim_t oldNN[2] = {0};
+
+    if (d0 == 0 || d1 == 0)
+        throw RipleyException("Domain subdivisions must be positive");
+
+    for (int i = 0; i < 2; i++) {
+        m_NE[i] *= subdivisions;
+        oldNN[i] = m_NN[i];
+        m_NN[i] = m_NE[i] + 1;
+        m_gNE[i] *= subdivisions;
+        m_ownNE[i] *= subdivisions;
+        m_dx[i] /= subdivisions;
+        m_faceCount[i] *= subdivisions;
+        m_faceCount[2+i] *= subdivisions;
+        m_offset[i] *= subdivisions;
+    }
+    populateSampleIds();
+    
+    const dim_t nDirac = m_diracPoints.size();
+#pragma omp parallel for
+    for (int i = 0; i < nDirac; i++) {
+        const dim_t node = m_diracPoints[i].node;
+        const dim_t x = node % oldNN[0];
+        const dim_t y = node / oldNN[0];
+        m_diracPoints[i].node = INDEX2(x*subdivisions, y*subdivisions, m_NN[0]);
+        m_diracPointNodeIDs[i] = m_diracPoints[i].node;
+    }
+}
+
+MultiRectangle::~MultiRectangle()
+{
+}
+
+void MultiRectangle::validateInterpolationAcross(int fsType_source,
+        const escript::AbstractDomain& domain, int fsType_target) const
+{
+    const MultiRectangle *other = dynamic_cast<const MultiRectangle *>(&domain);
+    if (other == NULL)
+        throw RipleyException("Invalid interpolation: domains must both be instances of MultiRectangle");
+
+    const double *len = other->getLength();
+    const int *subdivs = other->getNumSubdivisionsPerDim();
+    const int *elements = other->getNumElementsPerDim();
+    const unsigned int level = other->getNumSubdivisionsPerElement();
+    const unsigned int factor = m_subdivisions > level ? m_subdivisions/level : level/m_subdivisions;
+    if ((factor & (factor - 1)) != 0) //factor == 2**x
+        throw RipleyException("Invalid interpolation: elemental subdivisions of each domain must be powers of two");
+
+    if (other->getMPIComm() != m_mpiInfo->comm)
+        throw RipleyException("Invalid interpolation: Domains are on different communicators");
+    for (int i = 0; i < m_numDim; i++) {
+        if (m_length[i] != len[i]) {
+            throw RipleyException("Invalid interpolation: domain length mismatch");
+        }
+        if (m_NX[i] != subdivs[i]) {
+            throw RipleyException("Invalid interpolation: domain process subdivision mismatch");
+        }
+        if (m_subdivisions > level) {
+            if (m_NE[i]/elements[i] != factor) {
+            fprintf(stderr, "m_ownNE[i]/elements[i] = %d != %d\n", m_ownNE[i]/elements[i], factor);
+                throw RipleyException("Invalid interpolation: element factor mismatch");
+            }
+        } else {
+            if (elements[i]/m_NE[i] != factor) {
+                throw RipleyException("Invalid interpolation: element factor mismatch");
+            }
+        }
+    }
+}
+
+void MultiRectangle::interpolateNodesToNodesFiner(const escript::Data& source,
+        escript::Data& target, const MultiRectangle& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t NN0 = m_NN[0], NN1 = m_NN[1], otherNN0 = other.getNumNodesPerDim()[0];
+    const dim_t numComp = source.getDataPointSize();
+#pragma omp parallel for
+    for (dim_t ny = 0; ny < NN1 - 1; ny++) { //source nodes
+        for (dim_t nx = 0; nx < NN0 - 1; nx++) {
+            const double *x0y0 = source.getSampleDataRO(ny*NN0 + nx);
+            const double *x0y1 = source.getSampleDataRO((ny+1)*NN0 + nx);
+            const double *x1y0 = source.getSampleDataRO(ny*NN0 + nx + 1);
+            const double *x1y1 = source.getSampleDataRO((ny+1)*NN0 + nx + 1);
+            const double origin[2] = {getLocalCoordinate(nx, 0), getLocalCoordinate(ny, 1)};
+            for (int sy = 0; sy < scaling + 1; sy++) { //target nodes
+                const double y = (other.getLocalCoordinate(ny*scaling+sy, 1) - origin[1]) / m_dx[1];
+                for (int sx = 0; sx < scaling + 1; sx++) {
+                    const double x = (other.getLocalCoordinate(nx*scaling+sx, 0) - origin[0]) / m_dx[0];
+                    double *out = target.getSampleDataRW(nx*scaling+sx + (ny*scaling+sy)*otherNN0);
+                    for (int comp = 0; comp < numComp; comp++) {
+                        out[comp] = x0y0[comp]*(1-x)*(1-y) + x1y0[comp]*x*(1-y) + x0y1[comp]*(1-x)*y + x1y1[comp]*x*y;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiRectangle::interpolateReducedToElementsFiner(const escript::Data& source,
+        escript::Data& target, const MultiRectangle& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t numComp = source.getDataPointSize();
+    //for each of ours
+#pragma omp parallel for
+    for (dim_t ey = 0; ey < m_NE[1]; ey++) {
+        for (dim_t ex = 0; ex < m_NE[0]; ex++) {
+            const double *in = source.getSampleDataRO(ex + ey*m_NE[0]);
+            //for each subelement
+            for (dim_t sy = 0; sy < scaling; sy++) {
+                const dim_t ty = ey*scaling + sy;
+                for (dim_t sx = 0; sx < scaling; sx++) {
+                    const dim_t tx = ex*scaling + sx;
+                    double *out = target.getSampleDataRW(tx + ty*m_NE[0]*scaling);
+                    for (dim_t comp = 0; comp < numComp; comp++) {
+                        const double quadvalue = in[comp];
+                        out[INDEX3(comp, 0, 0, numComp, 2)] = quadvalue;
+                        out[INDEX3(comp, 0, 1, numComp, 2)] = quadvalue;
+                        out[INDEX3(comp, 1, 0, numComp, 2)] = quadvalue;
+                        out[INDEX3(comp, 1, 1, numComp, 2)] = quadvalue;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiRectangle::interpolateReducedToReducedFiner(const escript::Data& source,
+        escript::Data& target, const MultiRectangle& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t numComp = source.getDataPointSize();
+    //for each of ours
+#pragma omp parallel for
+    for (dim_t ey = 0; ey < m_NE[1]; ey++) {
+        for (dim_t ex = 0; ex < m_NE[0]; ex++) {
+            const double *in = source.getSampleDataRO(ex + ey*m_NE[0]);
+            //for each subelement
+            for (dim_t sy = 0; sy < scaling; sy++) {
+                const dim_t ty = ey*scaling + sy;
+                for (dim_t sx = 0; sx < scaling; sx++) {
+                    const dim_t tx = ex*scaling + sx;
+                    double *out = target.getSampleDataRW(tx + ty*m_NE[0]*scaling);
+                    for (dim_t comp = 0; comp < numComp; comp++) {
+                        out[comp] = in[comp];
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiRectangle::interpolateNodesToElementsFiner(const escript::Data& source,
+        escript::Data& target, const MultiRectangle& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t NE0 = m_NE[0], NE1 = m_NE[1];
+    const dim_t numComp = source.getDataPointSize();
+#pragma omp parallel for
+    for (dim_t ey = 0; ey < NE1; ey++) { //source nodes
+        for (dim_t ex = 0; ex < NE0; ex++) {
+            const double *x0y0 = source.getSampleDataRO(ey*(NE0+1) + ex);
+            const double *x0y1 = source.getSampleDataRO((ey+1)*(NE0+1) + ex);
+            const double *x1y0 = source.getSampleDataRO(ey*(NE0+1) + ex + 1);
+            const double *x1y1 = source.getSampleDataRO((ey+1)*(NE0+1) + ex + 1);
+            const double origin[2] = {getLocalCoordinate(ex, 0), getLocalCoordinate(ey, 1)};
+            for (int sy = 0; sy < scaling; sy++) { //target elements
+                for (int sx = 0; sx < scaling; sx++) {
+                    const double x1 = (other.getLocalCoordinate(ex*scaling+sx, 0) - origin[0]) / m_dx[0] + FIRST_QUAD/scaling;
+                    const double x2 = x1 + (SECOND_QUAD - FIRST_QUAD)/scaling;
+                    const double y1 = (other.getLocalCoordinate(ey*scaling+sy, 1) - origin[1]) / m_dx[1] + FIRST_QUAD/scaling;
+                    const double y2 = y1 + (SECOND_QUAD - FIRST_QUAD)/scaling;
+                    double *out = target.getSampleDataRW(ex*scaling+sx + (ey*scaling+sy)*NE0*scaling);
+                    for (int comp = 0; comp < numComp; comp++) {
+                        out[INDEX3(comp, 0, 0, numComp, 2)] = x0y0[comp]*(1-x1)*(1-y1) + x1y0[comp]*x1*(1-y1) + x0y1[comp]*(1-x1)*y1 + x1y1[comp]*x1*y1;
+                        out[INDEX3(comp, 0, 1, numComp, 2)] = x0y0[comp]*(1-x1)*(1-y2) + x1y0[comp]*x1*(1-y2) + x0y1[comp]*(1-x1)*y2 + x1y1[comp]*x1*y2;
+                        out[INDEX3(comp, 1, 0, numComp, 2)] = x0y0[comp]*(1-x2)*(1-y1) + x1y0[comp]*x2*(1-y1) + x0y1[comp]*(1-x2)*y1 + x1y1[comp]*x2*y1;
+                        out[INDEX3(comp, 1, 1, numComp, 2)] = x0y0[comp]*(1-x2)*(1-y2) + x1y0[comp]*x2*(1-y2) + x0y1[comp]*(1-x2)*y2 + x1y1[comp]*x2*y2;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiRectangle::interpolateElementsToElementsCoarser(const escript::Data& source,
+        escript::Data& target, const MultiRectangle& other) const
+{
+    const int scaling = m_subdivisions/other.getNumSubdivisionsPerElement();
+    const double scaling_volume = (1./scaling)*(1./scaling);
+    const dim_t *theirNE = other.getNumElementsPerDim();
+    const dim_t numComp = source.getDataPointSize();
+
+    std::vector<double> points(scaling*2, 0);
+    std::vector<double> first_lagrange(scaling*2, 1);
+    std::vector<double> second_lagrange(scaling*2, 1);
+    
+    for (int i = 0; i < scaling*2; i+=2) {
+        points[i] = (i/2 + FIRST_QUAD)/scaling;
+        points[i+1] = (i/2 + SECOND_QUAD)/scaling;
+    }
+    
+    for (int i = 0; i < scaling*2; i++) {
+        first_lagrange[i] = (points[i] - SECOND_QUAD) / (FIRST_QUAD - SECOND_QUAD);
+        second_lagrange[i] = (points[i] - FIRST_QUAD) / (SECOND_QUAD - FIRST_QUAD);
+    }
+    
+    //for each of theirs
+#pragma omp parallel for
+    for (dim_t ty = 0; ty < theirNE[1]; ty++) {
+        for (dim_t tx = 0; tx < theirNE[0]; tx++) {
+            double *out = target.getSampleDataRW(tx + ty*theirNE[0]);
+            //for each subelement
+            for (dim_t sy = 0; sy < scaling; sy++) {
+                const dim_t ey = ty*scaling + sy;
+                for (dim_t sx = 0; sx < scaling; sx++) {
+                    const dim_t ex = tx*scaling + sx;
+                    const double *in = source.getSampleDataRO(ex + ey*m_NE[0]);
+                    for (int quad = 0; quad < 4; quad++) {
+                        int lx = sx*2 + quad%2;
+                        int ly = sy*2 + quad/2;
+                        for (dim_t comp = 0; comp < numComp; comp++) {
+                            const double quadvalue = scaling_volume * in[comp + quad*numComp];
+                            out[INDEX3(comp, 0, 0, numComp, 2)] += quadvalue * first_lagrange[lx] * first_lagrange[ly];
+                            out[INDEX3(comp, 0, 1, numComp, 2)] += quadvalue * first_lagrange[lx] * second_lagrange[ly];
+                            out[INDEX3(comp, 1, 0, numComp, 2)] += quadvalue * second_lagrange[lx] * first_lagrange[ly];
+                            out[INDEX3(comp, 1, 1, numComp, 2)] += quadvalue * second_lagrange[lx] * second_lagrange[ly];
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+void MultiRectangle::interpolateElementsToElementsFiner(const escript::Data& source,
+        escript::Data& target, const MultiRectangle& other) const
+{
+    const int scaling = other.getNumSubdivisionsPerElement()/m_subdivisions;
+    const dim_t numComp = source.getDataPointSize();
+
+    std::vector<double> points(scaling*2, 0);
+    std::vector<double> lagranges(scaling*4, 1);
+
+    for (int i = 0; i < scaling*2; i+=2) {
+        points[i] = (i/2 + FIRST_QUAD)/scaling;
+        points[i+1] = (i/2 + SECOND_QUAD)/scaling;
+    }
+    for (int i = 0; i < scaling*2; i++) {
+        lagranges[i] = (points[i] - SECOND_QUAD) / (FIRST_QUAD - SECOND_QUAD);
+        lagranges[i + 2*scaling] = (points[i] - FIRST_QUAD) / (SECOND_QUAD - FIRST_QUAD);
+    }
+    //for each of ours
+#pragma omp parallel for
+    for (dim_t ey = 0; ey < m_NE[1]; ey++) {
+        for (dim_t ex = 0; ex < m_NE[0]; ex++) {
+            const double *in = source.getSampleDataRO(ex + ey*m_NE[0]);
+            //for each subelement
+            for (dim_t sy = 0; sy < scaling; sy++) {
+                const dim_t ty = ey*scaling + sy;
+                for (dim_t sx = 0; sx < scaling; sx++) {
+                    const dim_t tx = ex*scaling + sx;
+                    double *out = target.getSampleDataRW(tx + ty*m_NE[0]*scaling);
+                    for (int quad = 0; quad < 4; quad++) {
+                        const int lx = scaling*2*(quad%2) + sx*2;
+                        const int ly = scaling*2*(quad/2) + sy*2;
+                        for (dim_t comp = 0; comp < numComp; comp++) {
+                            const double quadvalue = in[comp + quad*numComp];
+                            out[INDEX3(comp, 0, 0, numComp, 2)] += quadvalue * lagranges[lx] * lagranges[ly];
+                            out[INDEX3(comp, 0, 1, numComp, 2)] += quadvalue * lagranges[lx] * lagranges[ly+1];
+                            out[INDEX3(comp, 1, 0, numComp, 2)] += quadvalue * lagranges[lx+1] * lagranges[ly];
+                            out[INDEX3(comp, 1, 1, numComp, 2)] += quadvalue * lagranges[lx+1] * lagranges[ly+1];
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MultiRectangle::interpolateAcross(escript::Data& target,
+                                     const escript::Data& source) const
+{
+    const MultiRectangle *other =
+                dynamic_cast<const MultiRectangle *>(target.getDomain().get());
+    if (other == NULL)
+        throw RipleyException("Invalid interpolation: Domains must both be instances of MultiRectangle");
+    //shouldn't ever happen, but I want to know if it does
+    if (other == this)
+        throw RipleyException("interpolateAcross: this domain is the target");
+        
+    validateInterpolationAcross(source.getFunctionSpace().getTypeCode(),
+            *(target.getDomain().get()), target.getFunctionSpace().getTypeCode());
+    int fsSource = source.getFunctionSpace().getTypeCode();
+    int fsTarget = target.getFunctionSpace().getTypeCode();
+
+    std::stringstream msg;
+    msg << "Invalid interpolation: interpolation not implemented for function space "
+        << functionSpaceTypeAsString(fsSource)
+        << " -> "
+        << functionSpaceTypeAsString(fsTarget);
+    if (other->getNumSubdivisionsPerElement() > getNumSubdivisionsPerElement()) {
+        switch (fsSource) {
+            case Nodes:
+                switch (fsTarget) {
+                    case Nodes:
+                    case ReducedNodes:
+                    case DegreesOfFreedom:
+                    case ReducedDegreesOfFreedom:
+                        interpolateNodesToNodesFiner(source, target, *other);
+                        return;
+                    case Elements:
+                        interpolateNodesToElementsFiner(source, target, *other);
+                        return;
+                }
+                break;
+            case Elements:
+                switch (fsTarget) {
+                    case Elements:
+                        interpolateElementsToElementsFiner(source, target, *other);
+                        return;
+                }
+                break;
+            case ReducedElements:
+                switch (fsTarget) {
+                    case Elements:
+                        interpolateReducedToElementsFiner(source, target, *other);
+                        return;
+                }
+                break;
+        }
+        msg << " when target is a finer mesh";
+    } else {
+        switch (fsSource) {
+            case Nodes:
+                switch (fsTarget) {
+                    case Elements:
+                        escript::Data elements=escript::Vector(0., escript::function(*this), true);
+                        interpolateNodesOnElements(elements, source, false);
+                        interpolateElementsToElementsCoarser(elements, target, *other);
+                        return;
+                }
+                break;
+            case Elements:
+                switch (fsTarget) {
+                    case Elements:
+                        interpolateElementsToElementsCoarser(source, target, *other);
+                        return;
+                }
+                break;
+        }
+        msg << " when target is a coarser mesh";
+    }
+    throw RipleyException(msg.str());
+}
+
+string MultiRectangle::getDescription() const
+{
+    return "ripley::MultiRectangle";
+}
+
+bool MultiRectangle::operator==(const AbstractDomain& other) const
+{
+    const MultiRectangle* o=dynamic_cast<const MultiRectangle*>(&other);
+    if (o) {
+        return (RipleyDomain::operator==(other) &&
+                m_gNE[0]==o->m_gNE[0] && m_gNE[1]==o->m_gNE[1]
+                && m_origin[0]==o->m_origin[0] && m_origin[1]==o->m_origin[1]
+                && m_length[0]==o->m_length[0] && m_length[1]==o->m_length[1]
+                && m_NX[0]==o->m_NX[0] && m_NX[1]==o->m_NX[1]
+                && m_subdivisions==o->m_subdivisions);
+    }
+
+    return false;
+}
+
+void MultiRectangle::readNcGrid(escript::Data& out, string filename, string varname,
+            const ReaderParameters& params) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiRectangles cannot read datafiles");
+    Rectangle::readNcGrid(out, filename, varname, params);
+}
+
+void MultiRectangle::readBinaryGrid(escript::Data& out, string filename,
+                               const ReaderParameters& params) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiRectangles cannot read datafiles");
+    Rectangle::readBinaryGrid(out, filename, params);
+}
+
+#ifdef USE_BOOSTIO
+void MultiRectangle::readBinaryGridFromZipped(escript::Data& out, string filename,
+                               const ReaderParameters& params) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiRectangles cannot read datafiles");
+    Rectangle::readBinaryGridFromZipped(out, filename, params);
+}
+#endif
+
+void MultiRectangle::writeBinaryGrid(const escript::Data& in, string filename,
+                                int byteOrder, int dataType) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiRectangles cannot read datafiles");
+    Rectangle::writeBinaryGrid(in, filename, byteOrder, dataType);
+}
+
+void MultiRectangle::dump(const string& fileName) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Non-parent MultiRectangles dump not implemented");
+    Rectangle::dump(fileName);
+}
+
+void MultiRectangle::populateDofMap()
+{
+    const index_t left = getFirstInDim(0);
+    const index_t bottom = getFirstInDim(1);
+    const dim_t nDOF0 = getNumDOFInAxis(0);
+    const dim_t nDOF1 = getNumDOFInAxis(1);
+    // populate node->DOF mapping with own degrees of freedom.
+    // The rest is assigned in the loop further down
+    m_dofMap.assign(getNumNodes(), -7);
+#pragma omp parallel for
+    for (index_t i=bottom; i<bottom+nDOF1; i++) {
+        for (index_t j=left; j<left+nDOF0; j++) {
+            m_dofMap[i*m_NN[0]+j]=(i-bottom)*nDOF0+j-left;
+        }
+    }
+
+    // build list of shared components and neighbours by looping through
+    // all potential neighbouring ranks and checking if positions are
+    // within bounds
+    const dim_t numDOF=nDOF0*nDOF1;
+    m_colIndices.clear();
+    m_rowIndices.clear();
+    m_colIndices.resize(numDOF);
+    m_rowIndices.resize(getNumNodes() - numDOF);
+
+    RankVector neighbour;
+    IndexVector offsetInSharedSend(1,0);
+    IndexVector offsetInSharedRecv(1,0);
+    IndexVector sendShared, recvShared;
+    const int x=m_mpiInfo->rank%m_NX[0];
+    const int y=m_mpiInfo->rank/m_NX[0];
+    // numShared will contain the number of shared DOFs after the following
+    // blocks
+    dim_t numShared=0;
+    // sharing bottom edge
+    if (y > 0) {
+        neighbour.push_back((y-1)*m_NX[0] + x);
+        //joining edge, send and recv
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+nDOF0);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+nDOF0*m_subdivisions);
+        for (dim_t i=0; i < nDOF0; i++, numShared++) {
+            sendShared.push_back(i);
+            recvShared.push_back(numDOF+numShared);
+            m_dofMap[i+left]=numDOF + numShared;
+            const dim_t ind = i;
+            if (i > 0)
+                doublyLink(m_colIndices, m_rowIndices, ind - 1, numShared);
+            doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+            if (i < nDOF0 - 1)
+                doublyLink(m_colIndices, m_rowIndices, ind + 1, numShared);
+        }
+    
+        for (unsigned sy = 1; sy < m_subdivisions; sy++) {
+            for (dim_t i=0; i < nDOF0; i++, numShared++) {
+                recvShared.push_back(numDOF+numShared);
+                m_dofMap[left + i + sy*m_NN[0]] = numDOF + numShared;
+                const dim_t ind = i;
+                if (i > 0)
+                    doublyLink(m_colIndices, m_rowIndices, ind - 1, numShared);
+                doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+                if (i < nDOF0 - 1)
+                    doublyLink(m_colIndices, m_rowIndices, ind + 1, numShared);
+            }
+        }
+    }
+    // sharing top edge
+    if (y < m_NX[1] - 1) {
+        neighbour.push_back((y+1)*m_NX[0] + x);
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+nDOF0*m_subdivisions);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+nDOF0);
+        // add to send only
+        for (unsigned sy = 0; sy < m_subdivisions; sy++) {
+            for (dim_t i=0; i < nDOF0; i++) {
+                sendShared.push_back(numDOF-nDOF0*(m_subdivisions - sy) + i);
+            }
+        }
+        for (dim_t i=0; i < nDOF0; i++, numShared++) {
+            recvShared.push_back(numDOF+numShared);
+            m_dofMap[m_NN[0]*(m_NN[1]-1)+left+i]=numDOF+numShared;
+            const dim_t ind = numDOF-nDOF0+i;
+            if (i > 0)
+                doublyLink(m_colIndices, m_rowIndices, ind - 1, numShared);
+            doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+            if (i < nDOF0 - 1)
+                doublyLink(m_colIndices, m_rowIndices, ind + 1, numShared);
+        }
+    }
+    // sharing left edge
+    if (x > 0) {
+        neighbour.push_back(y*m_NX[0] + x-1);
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+nDOF1);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+nDOF1*m_subdivisions);
+        for (dim_t i=0; i < nDOF1; i++, numShared++) {
+            for (unsigned sx = 0; sx < m_subdivisions - 1; sx++, numShared++) {
+                recvShared.push_back(numDOF+numShared);
+                m_dofMap[(bottom+i)*m_NN[0] + sx] = numDOF + numShared;
+                const dim_t ind = i*nDOF0;
+                if (i > 0)
+                    doublyLink(m_colIndices, m_rowIndices, ind - nDOF0, numShared);
+                doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+                if (i < nDOF1 - 1)
+                    doublyLink(m_colIndices, m_rowIndices, ind + nDOF0, numShared);
+            }
+            sendShared.push_back(i*nDOF0);
+            recvShared.push_back(numDOF + numShared);
+            m_dofMap[(bottom+i)*m_NN[0] + m_subdivisions - 1]=numDOF + numShared;
+            const dim_t ind = i*nDOF0;
+            if (i > 0)
+                doublyLink(m_colIndices, m_rowIndices, ind - nDOF0, numShared);
+            doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+            if (i < nDOF1 - 1)
+                doublyLink(m_colIndices, m_rowIndices, ind + nDOF0, numShared);
+        }
+    }
+    // sharing right edge
+    if (x < m_NX[0] - 1) {
+        neighbour.push_back(y*m_NX[0] + x+1);
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+nDOF1*m_subdivisions);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+nDOF1);
+        for (dim_t i=0; i < nDOF1; i++, numShared++) {
+            for (unsigned sx = 0; sx < m_subdivisions - 1; sx++) {
+                sendShared.push_back((i+1)*nDOF0-(m_subdivisions - sx));
+            }
+            sendShared.push_back((i+1)*nDOF0-1);
+            recvShared.push_back(numDOF+numShared);
+            m_dofMap[(bottom+1+i)*m_NN[0]- 1]=numDOF+numShared;
+            const dim_t ind = (i+1)*nDOF0 - 1;
+            if (i > 0)
+                doublyLink(m_colIndices, m_rowIndices, ind - nDOF0, numShared);
+            doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+            if (i < nDOF1 - 1)
+                doublyLink(m_colIndices, m_rowIndices, ind + nDOF0, numShared);
+        }
+    }
+    // sharing bottom-left node
+    if (x > 0 && y > 0) {
+        neighbour.push_back((y-1)*m_NX[0] + x-1);
+        // sharing a node
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+1);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+m_subdivisions*m_subdivisions);
+        for (unsigned sy = 0; sy < m_subdivisions; sy++) {
+            for (unsigned sx = 0; sx < m_subdivisions; sx++, numShared++) {
+                m_dofMap[sx + sy*m_NN[0]] = numDOF + numShared;
+                recvShared.push_back(numDOF+numShared);
+                doublyLink(m_colIndices, m_rowIndices, 0, numShared);
+            }
+        }
+        sendShared.push_back(0);
+    }
+    // sharing top-left node
+    if (x > 0 && y < m_NX[1]-1) {
+        neighbour.push_back((y+1)*m_NX[0] + x-1);
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+m_subdivisions);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+m_subdivisions);
+        for (int s = 0; s < m_subdivisions; s++, numShared++) {
+            sendShared.push_back(numDOF - (m_subdivisions - s)*nDOF0);
+            recvShared.push_back(numDOF + numShared);
+            m_dofMap[m_NN[0]*(m_NN[1]-1) + s] = numDOF + numShared;
+            if (s > 0)
+                doublyLink(m_colIndices, m_rowIndices, numDOF - (m_subdivisions - s + 1)*nDOF0, numShared);
+            doublyLink(m_colIndices, m_rowIndices, numDOF - (m_subdivisions - s)*nDOF0, numShared);
+            if (s < m_subdivisions - 1)
+                doublyLink(m_colIndices, m_rowIndices, numDOF - (m_subdivisions - s - 1)*nDOF0, numShared);            
+        }
+    }
+    // sharing bottom-right node
+    if (x < m_NX[0]-1 && y > 0) {
+        neighbour.push_back((y-1)*m_NX[0] + x+1);
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+m_subdivisions);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+m_subdivisions);
+        for (int s = 0; s < m_subdivisions; s++, numShared++) {
+            recvShared.push_back(numDOF+numShared);
+            m_dofMap[(s+1)*m_NN[0] - 1] = numDOF + numShared;
+            sendShared.push_back(nDOF0-(m_subdivisions-s));
+            const dim_t ind = nDOF0 - (m_subdivisions - s);
+            if (s > 0)
+                doublyLink(m_colIndices, m_rowIndices, ind - 1, numShared);
+            doublyLink(m_colIndices, m_rowIndices, ind, numShared);
+            if (s < m_subdivisions - 1)
+                doublyLink(m_colIndices, m_rowIndices, ind + 1, numShared);
+        }
+    }
+    // sharing top-right node
+    if (x < m_NX[0]-1 && y < m_NX[1]-1) {
+        neighbour.push_back((y+1)*m_NX[0] + x+1);
+        offsetInSharedSend.push_back(offsetInSharedSend.back()+m_subdivisions*m_subdivisions);
+        offsetInSharedRecv.push_back(offsetInSharedRecv.back()+1);
+        for (unsigned sy = 0; sy < m_subdivisions; sy++) {
+            for (unsigned sx = 0; sx < m_subdivisions; sx++) {
+                sendShared.push_back(numDOF-(m_subdivisions - sy - 1)*nDOF0 - (m_subdivisions - sx));
+            }
+        }
+        recvShared.push_back(numDOF+numShared);
+        m_dofMap[m_NN[0]*m_NN[1]-1]=numDOF+numShared;
+        doublyLink(m_colIndices, m_rowIndices, numDOF-1, numShared);
+        ++numShared;
+    }
+
+    // TODO: paso::SharedComponents should take vectors to avoid this
+    Esys_MPI_rank* neighPtr = NULL;
+    index_t* sendPtr = NULL;
+    index_t* recvPtr = NULL;
+    if (neighbour.size() > 0) {
+        neighPtr = &neighbour[0];
+        sendPtr = &sendShared[0];
+        recvPtr = &recvShared[0];
+    }
+    // create connector
+    paso::SharedComponents_ptr snd_shcomp(new paso::SharedComponents(
+            numDOF, neighbour.size(), neighPtr, sendPtr,
+            &offsetInSharedSend[0], 1, 0, m_mpiInfo));
+    paso::SharedComponents_ptr rcv_shcomp(new paso::SharedComponents(
+            numDOF, neighbour.size(), neighPtr, recvPtr,
+            &offsetInSharedRecv[0], 1, 0, m_mpiInfo));
+    m_connector.reset(new paso::Connector(snd_shcomp, rcv_shcomp));
+}
+
+void MultiRectangle::populateSampleIds()
+{
+    // degrees of freedom are numbered from left to right, bottom to top in
+    // each rank, continuing on the next rank (ranks also go left-right,
+    // bottom-top).
+    // This means rank 0 has id 0...n0-1, rank 1 has id n0...n1-1 etc. which
+    // helps when writing out data rank after rank.
+
+    // build node distribution vector first.
+    // rank i owns m_nodeDistribution[i+1]-nodeDistribution[i] nodes which is
+    // constant for all ranks in this implementation
+    m_nodeDistribution.assign(m_mpiInfo->size+1, 0);
+    const dim_t numDOF=getNumDOF();
+    for (dim_t k=1; k<m_mpiInfo->size; k++) {
+        m_nodeDistribution[k]=k*numDOF;
+    }
+    m_nodeDistribution[m_mpiInfo->size]=getNumDataPointsGlobal();
+    try {
+        m_nodeId.resize(getNumNodes());
+        m_dofId.resize(numDOF);
+        m_elementId.resize(getNumElements());
+    } catch (const std::length_error& le) {
+        throw RipleyException("The system does not have sufficient memory for a domain of this size.");
+    }
+
+    // populate face element counts
+    //left
+    if (m_offset[0]==0)
+        m_faceCount[0]=m_NE[1];
+    else
+        m_faceCount[0]=0;
+    //right
+    if (m_mpiInfo->rank%m_NX[0]==m_NX[0]-1)
+        m_faceCount[1]=m_NE[1];
+    else
+        m_faceCount[1]=0;
+    //bottom
+    if (m_offset[1]==0)
+        m_faceCount[2]=m_NE[0];
+    else
+        m_faceCount[2]=0;
+    //top
+    if (m_mpiInfo->rank/m_NX[0]==m_NX[1]-1)
+        m_faceCount[3]=m_NE[0];
+    else
+        m_faceCount[3]=0;
+
+    const dim_t NFE = getNumFaceElements();
+    m_faceId.resize(NFE);
+
+    const index_t left = getFirstInDim(0);
+    const index_t bottom = getFirstInDim(1);
+    const dim_t nDOF0 = getNumDOFInAxis(0);
+    const dim_t nDOF1 = getNumDOFInAxis(1);
+    const dim_t NE0 = m_NE[0];
+    const dim_t NE1 = m_NE[1];
+
+#define globalNodeId(x,y) \
+    ((m_offset[0]+x)/nDOF0)*nDOF0*nDOF1+(m_offset[0]+x)%nDOF0 \
+    + ((m_offset[1]+y)/nDOF1)*nDOF0*nDOF1*m_NX[0]+((m_offset[1]+y)%nDOF1)*nDOF0
+
+    // set corner id's outside the parallel region
+    m_nodeId[0] = globalNodeId(0, 0);
+    m_nodeId[m_NN[0]-1] = globalNodeId(m_NN[0]-1, 0);
+    m_nodeId[m_NN[0]*(m_NN[1]-1)] = globalNodeId(0, m_NN[1]-1);
+    m_nodeId[m_NN[0]*m_NN[1]-1] = globalNodeId(m_NN[0]-1,m_NN[1]-1);
+#undef globalNodeId
+
+#pragma omp parallel
+    {
+        // populate degrees of freedom and own nodes (identical id)
+#pragma omp for nowait
+        for (dim_t i=0; i<nDOF1; i++) {
+            for (dim_t j=0; j<nDOF0; j++) {
+                const index_t nodeIdx=j+left+(i+bottom)*m_NN[0];
+                const index_t dofIdx=j+i*nDOF0;
+                m_dofId[dofIdx] = m_nodeId[nodeIdx]
+                    = m_nodeDistribution[m_mpiInfo->rank]+dofIdx;
+            }
+        }
+
+        // populate the rest of the nodes (shared with other ranks)
+        if (m_faceCount[0]==0) { // left column
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF1; i++) {
+                const index_t nodeIdx=(i+bottom)*m_NN[0];
+                const index_t dofId=(i+1)*nDOF0-1;
+                m_nodeId[nodeIdx]
+                    = m_nodeDistribution[m_mpiInfo->rank-1]+dofId;
+            }
+        }
+        if (m_faceCount[1]==0) { // right column
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF1; i++) {
+                const index_t nodeIdx=(i+bottom+1)*m_NN[0]-1;
+                const index_t dofId=i*nDOF0;
+                m_nodeId[nodeIdx]
+                    = m_nodeDistribution[m_mpiInfo->rank+1]+dofId;
+            }
+        }
+        if (m_faceCount[2]==0) { // bottom row
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF0; i++) {
+                const index_t nodeIdx=i+left;
+                const index_t dofId=nDOF0*(nDOF1-1)+i;
+                m_nodeId[nodeIdx]
+                    = m_nodeDistribution[m_mpiInfo->rank-m_NX[0]]+dofId;
+            }
+        }
+        if (m_faceCount[3]==0) { // top row
+#pragma omp for nowait
+            for (dim_t i=0; i<nDOF0; i++) {
+                const index_t nodeIdx=m_NN[0]*(m_NN[1]-1)+i+left;
+                const index_t dofId=i;
+                m_nodeId[nodeIdx]
+                    = m_nodeDistribution[m_mpiInfo->rank+m_NX[0]]+dofId;
+            }
+        }
+
+        // populate element id's
+#pragma omp for nowait
+        for (dim_t i1=0; i1<NE1; i1++) {
+            for (dim_t i0=0; i0<NE0; i0++) {
+                m_elementId[i0+i1*NE0]=(m_offset[1]+i1)*m_gNE[0]+m_offset[0]+i0;
+            }
+        }
+
+        // face elements
+#pragma omp for
+        for (dim_t k=0; k<NFE; k++)
+            m_faceId[k]=k;
+    } // end parallel section
+
+    m_nodeTags.assign(getNumNodes(), 0);
+    updateTagsInUse(Nodes);
+
+    m_elementTags.assign(getNumElements(), 0);
+    updateTagsInUse(Elements);
+
+    // generate face offset vector and set face tags
+    const index_t LEFT=1, RIGHT=2, BOTTOM=10, TOP=20;
+    const index_t faceTag[] = { LEFT, RIGHT, BOTTOM, TOP };
+    m_faceOffset.assign(4, -1);
+    m_faceTags.clear();
+    index_t offset=0;
+    for (size_t i=0; i<4; i++) {
+        if (m_faceCount[i]>0) {
+            m_faceOffset[i]=offset;
+            offset+=m_faceCount[i];
+            m_faceTags.insert(m_faceTags.end(), m_faceCount[i], faceTag[i]);
+        }
+    }
+    setTagMap("left", LEFT);
+    setTagMap("right", RIGHT);
+    setTagMap("bottom", BOTTOM);
+    setTagMap("top", TOP);
+    updateTagsInUse(FaceElements);
+
+    populateDofMap();
+}
+
+paso::SystemMatrixPattern_ptr MultiRectangle::getPasoMatrixPattern(
+                                                    bool reducedRowOrder,
+                                                    bool reducedColOrder) const
+{
+    if (m_pattern.get())
+        return m_pattern;
+
+    // first call - create pattern, then return
+    const dim_t numDOF = getNumDOF();
+    const dim_t numShared = getNumNodes() - numDOF;
+#pragma omp parallel for
+    for (dim_t i = 0; i < numShared; i++) {
+        sort(m_rowIndices[i].begin(), m_rowIndices[i].end());
+    }
+
+    // create main and couple blocks
+    paso::Pattern_ptr mainPattern = createPasoPattern(getConnections(), numDOF);
+    paso::Pattern_ptr colPattern = createPasoPattern(m_colIndices, numShared);
+    paso::Pattern_ptr rowPattern = createPasoPattern(m_rowIndices, numDOF);
+
+    // allocate paso distribution
+    paso::Distribution_ptr distribution(new paso::Distribution(m_mpiInfo,
+            const_cast<index_t*>(&m_nodeDistribution[0]), 1, 0));
+
+    // finally create the system matrix pattern
+    m_pattern.reset(new paso::SystemMatrixPattern(MATRIX_FORMAT_DEFAULT,
+            distribution, distribution, mainPattern, colPattern, rowPattern,
+            m_connector, m_connector));
+    return m_pattern;
+}
+
+RankVector MultiRectangle::getOwnerVector(int fsType) const
+{
+    if (m_subdivisions != 1)
+        throw RipleyException("Multiresolution domains only support ownership for the coarsest level");
+    return Rectangle::getOwnerVector(fsType);
+}
+
+dim_t MultiRectangle::findNode(const double *coords) const
+{
+    const dim_t NOT_MINE = -1;
+    //is the found element even owned by this rank
+    // (inside owned or shared elements but will map to an owned element)
+    for (int dim = 0; dim < m_numDim; dim++) {
+        double min = m_origin[dim] + m_offset[dim]* m_dx[dim]
+                - m_dx[dim]/2.; //allows for point outside mapping onto node
+        double max = m_origin[dim] + (m_offset[dim] + m_NE[dim])*m_dx[dim]
+                + m_dx[dim]/2.;
+        if (min > coords[dim] || max < coords[dim]) {
+            return NOT_MINE;
+        }
+    }
+    // get distance from origin
+    double x = coords[0] - m_origin[0];
+    double y = coords[1] - m_origin[1];
+
+    //check if the point is even inside the domain
+    if (x < 0 || y < 0 || x > m_length[0] || y > m_length[1])
+        return NOT_MINE;
+
+    // distance in elements
+    dim_t ex = (dim_t) floor((x + 0.01*m_dx[0]) / m_dx[0]);
+    dim_t ey = (dim_t) floor((y + 0.01*m_dx[1]) / m_dx[1]);
+    // set the min distance high enough to be outside the element plus a bit
+    dim_t closest = NOT_MINE;
+    double minDist = 1;
+    for (int dim = 0; dim < m_numDim; dim++) {
+        minDist += m_dx[dim]*m_dx[dim];
+    }
+    //find the closest node
+    for (int dx = 0; dx < 1; dx++) {
+        double xdist = (x - (ex + dx)*m_dx[0]);
+        for (int dy = 0; dy < 1; dy++) {
+            double ydist = (y - (ey + dy)*m_dx[1]);
+            double total = xdist*xdist + ydist*ydist;
+            if (total < minDist) {
+                closest = INDEX2(ex+dx-m_offset[0], ey+dy-m_offset[1], m_NN[0]);
+                minDist = total;
+            }
+        }
+    }
+    //if this happens, we've let a dirac point slip through, which is awful
+    if (closest == NOT_MINE) {
+        throw RipleyException("Unable to map appropriate dirac point to a node,"
+                " implementation problem in MultiRectangle::findNode()");
+    }
+    return closest;
+}
+
+} // end of namespace ripley
+
diff --git a/ripley/src/MultiRectangle.h b/ripley/src/MultiRectangle.h
new file mode 100644
index 0000000..f97d6e8
--- /dev/null
+++ b/ripley/src/MultiRectangle.h
@@ -0,0 +1,177 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#ifndef __RIPLEY_MULTIRECTANGLE_H__
+#define __RIPLEY_MULTIRECTANGLE_H__
+
+#include <ripley/Rectangle.h>
+
+namespace ripley {
+
+/**
+   \brief
+   Rectangle is the 2-dimensional implementation of a RipleyDomain.
+*/
+class RIPLEY_DLL_API MultiRectangle: public Rectangle
+{
+    friend class DefaultAssembler2D;
+    friend class WaveAssembler2D;
+    friend class LameAssembler2D;
+public:
+
+    /**
+       \brief creates a rectangular mesh with n0 x n1 elements over the
+              rectangle [x0,x1] x [y0,y1].
+       \param n0,n1 number of elements in each dimension
+       \param x0,y0,x1,y1 coordinates of bottom-left and top-right corners
+       \param d0,d1 number of subdivisions in each dimension
+    */
+    MultiRectangle(dim_t n0, dim_t n1, double x0, double y0, double x1, double y1,
+              int d0=-1, int d1=-1,
+              const std::vector<double>& points = std::vector<double>(),
+              const std::vector<int>& tags = std::vector<int>(),
+              const TagMap& tagnamestonums = TagMap(),
+              escript::SubWorld_ptr w=escript::SubWorld_ptr(),
+              unsigned int subdivisions = 1
+ 	    );
+
+    /**
+       \brief
+       Destructor.
+    */
+    ~MultiRectangle();
+
+    /**
+       \brief
+       interpolates data given on source onto target where source and target
+       are given on different domains
+    */
+    virtual void interpolateAcross(escript::Data& target,
+                                   const escript::Data& source) const;
+
+    /**
+       \brief
+       Checks that the given interpolation is possible, throw RipleyExceptions
+       if not
+    */
+    void validateInterpolationAcross(int fsType_source,
+              const escript::AbstractDomain& domain, int fsType_target) const;
+    
+    /**
+       \brief
+       returns a description for this domain
+    */
+    virtual std::string getDescription() const;
+
+    /**
+       \brief equality operator
+    */
+    virtual bool operator==(const escript::AbstractDomain& other) const;
+
+    /**
+       \brief
+       dumps the mesh to a file with the given name
+       \param filename The name of the output file
+    */
+    void dump(const std::string& filename) const;
+
+    /**
+    */
+    virtual void readNcGrid(escript::Data& out, std::string filename,
+            std::string varname, const ReaderParameters& params) const;
+
+    /**
+    */
+    virtual void readBinaryGrid(escript::Data& out, std::string filename,
+                                const ReaderParameters& params) const;
+
+#ifdef USE_BOOSTIO
+    virtual void readBinaryGridFromZipped(escript::Data& out, std::string filename,
+                                const ReaderParameters& params) const;
+#endif
+
+    /**
+    */
+    virtual void writeBinaryGrid(const escript::Data& in,
+                                 std::string filename,
+                                 int byteOrder, int dataType) const;
+
+    /**
+       \brief
+       returns the number of times each root element has been subdivided
+    */
+    virtual unsigned int getNumSubdivisionsPerElement() const { return m_subdivisions; }
+
+    /**
+       \brief
+       returns a vector of rank numbers where vec[i]=n means that rank n
+       'owns' element/face element i.
+    */
+    virtual RankVector getOwnerVector(int fsType) const;
+
+protected:
+    virtual void interpolateNodesToNodesFiner(const escript::Data& source, escript::Data& target, const MultiRectangle& other) const;
+    virtual void interpolateNodesToElementsFiner(const escript::Data& source, escript::Data& target, const MultiRectangle& other) const;
+
+    virtual void interpolateElementsToElementsCoarser(const escript::Data& source, escript::Data& target, const MultiRectangle& other) const;
+    virtual void interpolateElementsToElementsFiner(const escript::Data& source, escript::Data& target, const MultiRectangle& other) const;
+
+    virtual void interpolateReducedToElementsFiner(const escript::Data& source, escript::Data& target, const MultiRectangle& other) const;
+    virtual void interpolateReducedToReducedFiner(const escript::Data& source, escript::Data& target, const MultiRectangle& other) const;
+    virtual paso::SystemMatrixPattern_ptr getPasoMatrixPattern(
+                                                    bool reducedRowOrder,
+                                                    bool reducedColOrder) const;
+    virtual index_t getFirstInDim(unsigned axis) const;
+    virtual void populateSampleIds();
+    virtual dim_t getNumDOFInAxis(unsigned axis) const;
+    virtual dim_t getNumDOF() const;
+    virtual void populateDofMap();
+
+    virtual dim_t findNode(const double *coords) const;
+
+private:
+    mutable std::vector<IndexVector> m_colIndices;
+    mutable std::vector<IndexVector> m_rowIndices;
+    unsigned int m_subdivisions;
+};
+
+//protected
+inline dim_t MultiRectangle::getNumDOF() const
+{
+    return getNumDOFInAxis(0)*getNumDOFInAxis(1);
+}
+
+//protected
+inline dim_t MultiRectangle::getNumDOFInAxis(unsigned axis) const
+{
+    EsysAssert((axis < m_numDim), "Invalid axis");
+    dim_t res = m_ownNE[axis] + 1;
+    if (m_offset[axis] + m_NE[axis] < m_gNE[axis]) {
+        res--;
+    }
+    return res;
+}
+
+//protected
+index_t MultiRectangle::getFirstInDim(unsigned axis) const
+{
+    return m_offset[axis] == 0 ? 0 : m_subdivisions;
+}
+
+} // end of namespace ripley
+
+#endif // __RIPLEY_MULTIRECTANGLE_H__
+
diff --git a/ripley/src/Rectangle.cpp b/ripley/src/Rectangle.cpp
index b0e7e16..411f6ca 100644
--- a/ripley/src/Rectangle.cpp
+++ b/ripley/src/Rectangle.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,15 +14,19 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include <esysUtils/first.h>
+#include <esysUtils/esysFileWriter.h>
+#include <esysUtils/EsysRandom.h>
+
+#include <paso/SystemMatrix.h>
+
 #include <ripley/Rectangle.h>
 #include <ripley/DefaultAssembler2D.h>
 #include <ripley/LameAssembler2D.h>
 #include <ripley/WaveAssembler2D.h>
 #include <ripley/blocktools.h>
 #include <ripley/domainhelpers.h>
-#include <paso/SystemMatrix.h>
-#include <esysUtils/esysFileWriter.h>
-#include <esysUtils/EsysRandom.h>
 
 #ifdef USE_NETCDF
 #include <netcdfcpp.h>
@@ -35,16 +39,23 @@
 #endif
 #endif
 
+#include <boost/math/special_functions/fpclassify.hpp>	// for isnan
 #include <boost/scoped_array.hpp>
 
-#include <algorithm>
 #include <iomanip>
 #include <limits>
 
 namespace bp = boost::python;
-using namespace std;
+namespace bm = boost::math;
 using esysUtils::FileWriter;
 using escript::AbstractSystemMatrix;
+using std::vector;
+using std::string;
+using std::min;
+using std::max;
+using std::copy;
+using std::ios;
+using std::fill;
 
 namespace ripley {
 
@@ -57,7 +68,7 @@ Rectangle::Rectangle(dim_t n0, dim_t n1, double x0, double y0, double x1,
     RipleyDomain(2, w)
 {
     if (static_cast<long>(n0 + 1) * static_cast<long>(n1 + 1)
-            > numeric_limits<dim_t>::max())
+            > std::numeric_limits<dim_t>::max())
         throw RipleyException("The number of elements has overflowed, this "
                 "limit may be raised in future releases.");
 
@@ -110,8 +121,8 @@ Rectangle::Rectangle(dim_t n0, dim_t n1, double x0, double y0, double x1,
         throw RipleyException("Invalid number of spatial subdivisions");
 
     if (warn) {
-        cout << "Warning: Automatic domain subdivision (d0=" << d0 << ", d1="
-            << d1 << "). This may not be optimal!" << endl;
+        std::cout << "Warning: Automatic domain subdivision (d0=" << d0 << ", d1="
+            << d1 << "). This may not be optimal!" << std::endl;
     }
 
     double l0 = x1-x0;
@@ -122,14 +133,14 @@ Rectangle::Rectangle(dim_t n0, dim_t n1, double x0, double y0, double x1,
     if ((n0+1)%d0 > 0) {
         n0=(dim_t)round((float)(n0+1)/d0+0.5)*d0-1;
         l0=m_dx[0]*n0;
-        cout << "Warning: Adjusted number of elements and length. N0="
-            << n0 << ", l0=" << l0 << endl;
+        std::cout << "Warning: Adjusted number of elements and length. N0="
+            << n0 << ", l0=" << l0 << std::endl;
     }
     if ((n1+1)%d1 > 0) {
         n1=(dim_t)round((float)(n1+1)/d1+0.5)*d1-1;
         l1=m_dx[1]*n1;
-        cout << "Warning: Adjusted number of elements and length. N1="
-            << n1 << ", l1=" << l1 << endl;
+        std::cout << "Warning: Adjusted number of elements and length. N1="
+            << n1 << ", l1=" << l1 << std::endl;
     }
 
     if ((d0 > 1 && (n0+1)/d0<2) || (d1 > 1 && (n1+1)/d1<2))
@@ -304,7 +315,7 @@ void Rectangle::readNcGrid(escript::Data& out, string filename, string varname,
             const dim_t baseIndex = first0+x*params.multiplier[0]
                                   +(first1+y*params.multiplier[1])*myN0;
             const dim_t srcIndex = (y0+y_mult*y)*num0+(x0+x_mult*x);
-            if (!isnan(values[srcIndex])) {
+            if (!bm::isnan(values[srcIndex])) {
                 for (index_t m1=0; m1<params.multiplier[1]; m1++) {
                     for (index_t m0=0; m0<params.multiplier[0]; m0++) {
                         const dim_t dataIndex = baseIndex+m0+m1*myN0;
@@ -395,7 +406,7 @@ void Rectangle::readBinaryGridImpl(escript::Data& out, const string& filename,
         throw RipleyException("readBinaryGrid(): reversing not supported yet");
 
     // check file existence and size
-    ifstream f(filename.c_str(), ifstream::binary);
+    std::ifstream f(filename.c_str(), std::ifstream::binary);
     if (f.fail()) {
         throw RipleyException("readBinaryGrid(): cannot open file");
     }
@@ -474,7 +485,7 @@ void Rectangle::readBinaryGridImpl(escript::Data& out, const string& filename,
                                 byte_swap32(cval);
                             }
                         }
-                        if (!isnan(val)) {
+                        if (!bm::isnan(val)) {
                             for (int q=0; q<dpp; q++) {
                                 *dest++ = static_cast<double>(val);
                             }
@@ -506,7 +517,7 @@ void Rectangle::readBinaryGridZippedImpl(escript::Data& out, const string& filen
         throw RipleyException("readBinaryGrid(): invalid function space for output data object");
 
     // check file existence and size
-    ifstream f(filename.c_str(), ifstream::binary);
+    std::ifstream f(filename.c_str(), std::ifstream::binary);
     if (f.fail()) {
         throw RipleyException("readBinaryGridFromZipped(): cannot open file");
     }
@@ -567,7 +578,7 @@ void Rectangle::readBinaryGridZippedImpl(escript::Data& out, const string& filen
                             // this will alter val!!
                             byte_swap32(cval);
                         }
-                        if (!isnan(val)) {
+                        if (!bm::isnan(val)) {
                             for (int q=0; q<dpp; q++) {
                                 *dest++ = static_cast<double>(val);
                             }
@@ -651,7 +662,7 @@ void Rectangle::writeBinaryGridImpl(const escript::Data& in,
 
     for (index_t y=0; y<myN1; y++) {
         const dim_t fileofs = (offset0+(offset1+y)*totalN0)*sizeof(ValueType);
-        ostringstream oss;
+        std::ostringstream oss;
 
         for (index_t x=0; x<myN0; x++) {
             const double* sample = in.getSampleDataRO(y*myN0+x);
@@ -778,8 +789,8 @@ void Rectangle::dump(const string& fileName) const
         vector<string> tempstrings;
         vector<char*> names;
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/mesh";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/mesh";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -790,8 +801,8 @@ void Rectangle::dump(const string& fileName) const
         tempstrings.clear();
         names.clear();
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/nodeId";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/nodeId";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -801,8 +812,8 @@ void Rectangle::dump(const string& fileName) const
         tempstrings.clear();
         names.clear();
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/elementId";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/elementId";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -845,7 +856,7 @@ const dim_t* Rectangle::borrowSampleReferenceIDs(int fsType) const
             break;
     }
 
-    stringstream msg;
+    std::stringstream msg;
     msg << "borrowSampleReferenceIDs: invalid function space type " << fsType;
     throw RipleyException(msg.str());
 }
@@ -893,11 +904,51 @@ bool Rectangle::ownSample(int fsType, index_t id) const
             break;
     }
 
-    stringstream msg;
+    std::stringstream msg;
     msg << "ownSample: invalid function space type " << fsType;
     throw RipleyException(msg.str());
 }
 
+RankVector Rectangle::getOwnerVector(int fsType) const
+{
+    RankVector owner;
+    const Esys_MPI_rank rank = m_mpiInfo->rank;
+
+    if (fsType == Elements || fsType == ReducedElements) {
+        owner.assign(getNumElements(), rank);
+        if (m_faceCount[0] == 0) {
+            owner[0]=(m_faceCount[2]==0 ? rank-m_NX[0]-1 : rank-1);
+            for (dim_t i=1; i<m_NE[1]; i++)
+                owner[i*m_NE[0]] = rank-1;
+        }
+        if (m_faceCount[2]==0) {
+            const int first=(m_faceCount[0]==0 ? 1 : 0);
+            for (dim_t i=first; i<m_NE[0]; i++)
+                owner[i] = rank-m_NX[0];
+        }
+
+    } else if (fsType == FaceElements || fsType == ReducedFaceElements) {
+        owner.assign(getNumFaceElements(), rank);
+        if (m_faceCount[0] == 0) {
+            if (m_faceCount[2] > 0)
+                owner[m_faceCount[1]] = rank-1;
+            if (m_faceCount[3] > 0)
+                owner[m_faceCount[1]+m_faceCount[2]] = rank-1;
+        }
+        if (m_faceCount[2] == 0) {
+            if (m_faceCount[0] > 0)
+                owner[0] = rank-m_NX[0];
+            if (m_faceCount[1] > 0)
+                owner[m_faceCount[0]] = rank-m_NX[0];
+        }
+
+    } else {
+        throw RipleyException("getOwnerVector: only valid for element types");
+    }
+
+    return owner;
+}
+
 void Rectangle::setToNormal(escript::Data& out) const
 {
     const dim_t NE0=m_NE[0];
@@ -996,7 +1047,7 @@ void Rectangle::setToNormal(escript::Data& out) const
         } // end of parallel section
 
     } else {
-        stringstream msg;
+        std::stringstream msg;
         msg << "setToNormal: invalid function space type "
             << out.getFunctionSpace().getTypeCode();
         throw RipleyException(msg.str());
@@ -1058,7 +1109,7 @@ void Rectangle::setToSize(escript::Data& out) const
         } // end of parallel section
 
     } else {
-        stringstream msg;
+        std::stringstream msg;
         msg << "setToSize: invalid function space type "
             << out.getFunctionSpace().getTypeCode();
         throw RipleyException(msg.str());
@@ -1069,13 +1120,13 @@ void Rectangle::Print_Mesh_Info(const bool full) const
 {
     RipleyDomain::Print_Mesh_Info(full);
     if (full) {
-        cout << "     Id  Coordinates" << endl;
-        cout.precision(15);
-        cout.setf(ios::scientific, ios::floatfield);
+        std::cout << "     Id  Coordinates" << std::endl;
+        std::cout.precision(15);
+        std::cout.setf(ios::scientific, ios::floatfield);
         for (index_t i=0; i < getNumNodes(); i++) {
-            cout << "  " << setw(5) << m_nodeId[i]
+            std::cout << "  " << std::setw(5) << m_nodeId[i]
                 << "  " << getLocalCoordinate(i%m_NN[0], 0)
-                << "  " << getLocalCoordinate(i/m_NN[0], 1) << endl;
+                << "  " << getLocalCoordinate(i/m_NN[0], 1) << std::endl;
         }
     }
 }
@@ -1084,11 +1135,10 @@ void Rectangle::Print_Mesh_Info(const bool full) const
 //protected
 void Rectangle::assembleCoordinates(escript::Data& arg) const
 {
-    escriptDataC x = arg.getDataC();
     int numDim = m_numDim;
-    if (!isDataPointShapeEqual(&x, 1, &numDim))
+    if (&arg!=0 && !arg.isDataPointShapeEqual(1, &numDim))
         throw RipleyException("setToX: Invalid Data object shape");
-    if (!numSamplesEqual(&x, 1, getNumNodes()))
+    if (&arg!=0 && !arg.numSamplesEqual(1, getNumNodes()))
         throw RipleyException("setToX: Illegal number of samples in Data object");
 
     const dim_t NN0 = m_NN[0];
@@ -1316,8 +1366,8 @@ void Rectangle::assembleIntegrate(vector<double>& integrals,
                                   const escript::Data& arg) const
 {
     const dim_t numComp = arg.getDataPointSize();
-    const index_t left = (m_offset[0]==0 ? 0 : 1);
-    const index_t bottom = (m_offset[1]==0 ? 0 : 1);
+    const index_t left = getFirstInDim(0);
+    const index_t bottom = getFirstInDim(1);
     const int fs=arg.getFunctionSpace().getTypeCode();
     if (fs == Elements && arg.actsExpanded()) {
 #pragma omp parallel
@@ -1479,7 +1529,7 @@ IndexVector Rectangle::getDiagonalIndices(bool upperOnly) const
         ret.resize(5);
     else
         ret.resize(9);
-    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
+    const dim_t nDOF0 = getNumDOFInAxis(0);
     size_t idx = 0;
     for (int i1=-1; i1<2; i1++) {
         for (int i0=-1; i0<2; i0++) {
@@ -1498,10 +1548,10 @@ void Rectangle::nodesToDOF(escript::Data& out, const escript::Data& in) const
     const dim_t numComp = in.getDataPointSize();
     out.requireWrite();
 
-    const index_t left = (m_offset[0]==0 ? 0 : 1);
-    const index_t bottom = (m_offset[1]==0 ? 0 : 1);
-    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
-    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    const index_t left = getFirstInDim(0);
+    const index_t bottom = getFirstInDim(1);
+    const dim_t nDOF0 = getNumDOFInAxis(0);
+    const dim_t nDOF1 = getNumDOFInAxis(1);
 #pragma omp parallel for
     for (index_t i=0; i<nDOF1; i++) {
         for (index_t j=0; j<nDOF0; j++) {
@@ -1608,7 +1658,7 @@ void Rectangle::populateSampleIds()
         m_nodeId.resize(getNumNodes());
         m_dofId.resize(numDOF);
         m_elementId.resize(getNumElements());
-    } catch (const length_error& le) {
+    } catch (const std::length_error& le) {
         throw RipleyException("The system does not have sufficient memory for a domain of this size.");
     }
 
@@ -1637,10 +1687,10 @@ void Rectangle::populateSampleIds()
     const dim_t NFE = getNumFaceElements();
     m_faceId.resize(NFE);
 
-    const index_t left = (m_offset[0]==0 ? 0 : 1);
-    const index_t bottom = (m_offset[1]==0 ? 0 : 1);
-    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
-    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    const index_t left = getFirstInDim(0);
+    const index_t bottom = getFirstInDim(1);
+    const dim_t nDOF0 = getNumDOFInAxis(0);
+    const dim_t nDOF1 = getNumDOFInAxis(1);
     const dim_t NE0 = m_NE[0];
     const dim_t NE1 = m_NE[1];
 
@@ -1753,8 +1803,8 @@ vector<IndexVector> Rectangle::getConnections() const
 {
     // returns a vector v of size numDOF where v[i] is a vector with indices
     // of DOFs connected to i (up to 9 in 2D)
-    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
-    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
+    const dim_t nDOF0 = getNumDOFInAxis(0);
+    const dim_t nDOF1 = getNumDOFInAxis(1);
     const dim_t M = nDOF0*nDOF1;
     vector<IndexVector> indices(M);
 
@@ -1778,10 +1828,10 @@ vector<IndexVector> Rectangle::getConnections() const
 //private
 void Rectangle::populateDofMap()
 {
-    const dim_t nDOF0 = (m_gNE[0]+1)/m_NX[0];
-    const dim_t nDOF1 = (m_gNE[1]+1)/m_NX[1];
-    const index_t left = (m_offset[0]==0 ? 0 : 1);
-    const index_t bottom = (m_offset[1]==0 ? 0 : 1);
+    const dim_t nDOF0 = getNumDOFInAxis(0);
+    const dim_t nDOF1 = getNumDOFInAxis(1);
+    const index_t left = getFirstInDim(0);
+    const index_t bottom = getFirstInDim(1);
 
     // populate node->DOF mapping with own degrees of freedom.
     // The rest is assigned in the loop further down
@@ -1908,22 +1958,22 @@ void Rectangle::populateDofMap()
 
     // useful debug output
     /*
-    cout << "--- rcv_shcomp ---" << endl;
-    cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << endl;
+    std::cout << "--- rcv_shcomp ---" << std::endl;
+    std::cout << "numDOF=" << numDOF << ", numNeighbors=" << neighbour.size() << std::endl;
     for (size_t i=0; i<neighbour.size(); i++) {
-        cout << "neighbor[" << i << "]=" << neighbour[i]
-            << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << endl;
+        std::cout << "neighbor[" << i << "]=" << neighbour[i]
+            << " offsetInShared[" << i+1 << "]=" << offsetInShared[i+1] << std::endl;
     }
     for (size_t i=0; i<recvShared.size(); i++) {
-        cout << "shared[" << i << "]=" << recvShared[i] << endl;
+        std::cout << "shared[" << i << "]=" << recvShared[i] << std::endl;
     }
-    cout << "--- snd_shcomp ---" << endl;
+    std::cout << "--- snd_shcomp ---" << std::endl;
     for (size_t i=0; i<sendShared.size(); i++) {
-        cout << "shared[" << i << "]=" << sendShared[i] << endl;
+        std::cout << "shared[" << i << "]=" << sendShared[i] << std::endl;
     }
-    cout << "--- dofMap ---" << endl;
+    std::cout << "--- dofMap ---" << std::endl;
     for (size_t i=0; i<m_dofMap.size(); i++) {
-        cout << "m_dofMap[" << i << "]=" << m_dofMap[i] << endl;
+        std::cout << "m_dofMap[" << i << "]=" << m_dofMap[i] << std::endl;
     }
     */
 }
diff --git a/ripley/src/Rectangle.h b/ripley/src/Rectangle.h
index 35141c0..6cf6377 100644
--- a/ripley/src/Rectangle.h
+++ b/ripley/src/Rectangle.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -112,7 +112,7 @@ public:
        \brief
        returns true if this rank owns the sample id.
     */
-    virtual bool ownSample(int fs_code, index_t id) const;
+    virtual bool ownSample(int fsType, index_t id) const;
 
     /**
        \brief
@@ -187,14 +187,15 @@ public:
 
     /**
      * \brief 
-       Returns a Data object filled with random data passed through filter.
+       returns a Data object filled with random data passed through filter.
     */ 
     virtual escript::Data randomFill(const escript::DataTypes::ShapeType& shape,
-       const escript::FunctionSpace& what, long seed, const boost::python::tuple& filter) const;
+                                 const escript::FunctionSpace& what, long seed,
+                                 const boost::python::tuple& filter) const;
     
     /**
        \brief
-       Creates and returns an assembler of the requested type.
+       creates and returns an assembler of the requested type.
     */
     virtual Assembler_ptr createAssembler(std::string type,
                                           const DataMap& options) const;
@@ -211,11 +212,21 @@ public:
     */
     const double *getElementLength() const { return m_dx; }
 
+    /**
+       \brief
+       returns a vector of rank numbers where vec[i]=n means that rank n
+       'owns' element/face element i.
+    */
+    virtual RankVector getOwnerVector(int fsType) const;
+
 protected:
     virtual dim_t getNumNodes() const;
     virtual dim_t getNumElements() const;
     virtual dim_t getNumFaceElements() const;
     virtual dim_t getNumDOF() const;
+    virtual dim_t getNumDOFInAxis(unsigned axis) const;
+    virtual index_t getFirstInDim(unsigned axis) const;
+
     virtual IndexVector getDiagonalIndices(bool upperOnly) const;
     virtual void assembleCoordinates(escript::Data& arg) const;
     virtual void assembleGradient(escript::Data& out,
@@ -233,11 +244,10 @@ protected:
     virtual void dofToNodes(escript::Data& out, const escript::Data& in) const;
     virtual dim_t getDofOfNode(dim_t node) const;
 
-private:
-    void populateSampleIds();
-    void populateDofMap();
-    std::vector<IndexVector> getConnections() const;
-    void addToMatrixAndRHS(escript::AbstractSystemMatrix* S, escript::Data& F,
+    virtual void populateSampleIds();
+    virtual void populateDofMap();
+    virtual std::vector<IndexVector> getConnections() const;
+    virtual void addToMatrixAndRHS(escript::AbstractSystemMatrix* S, escript::Data& F,
            const DoubleVector& EM_S, const DoubleVector& EM_F,
            bool addS, bool addF, index_t firstNode, int nEq=1, int nComp=1) const;
 
@@ -253,7 +263,7 @@ private:
     void writeBinaryGridImpl(const escript::Data& in,
                              const std::string& filename, int byteOrder) const;
 
-    dim_t findNode(const double *coords) const;
+    virtual dim_t findNode(const double *coords) const;
 
     
     escript::Data randomFillWorker(const escript::DataTypes::ShapeType& shape,
@@ -327,8 +337,6 @@ inline dim_t Rectangle::getNumDataPointsGlobal() const
 inline double Rectangle::getLocalCoordinate(index_t index, int dim) const
 {
     EsysAssert((dim>=0 && dim<2), "'dim' out of bounds");
-    if (index < 0 || index >= m_NN[dim])
-fprintf(stderr, "about to break with index: %d and dim %d\n", index, dim);
     EsysAssert((index>=0 && index<m_NN[dim]), "'index' out of bounds");
     return m_origin[dim]+m_dx[dim]*(m_offset[dim]+index);
 }
@@ -348,6 +356,13 @@ inline dim_t Rectangle::getNumDOF() const
 }
 
 //protected
+inline dim_t Rectangle::getNumDOFInAxis(unsigned axis) const
+{
+    EsysAssert((axis < m_numDim), "Invalid axis");
+    return (m_gNE[axis]+1)/m_NX[axis];
+}
+
+//protected
 inline dim_t Rectangle::getNumNodes() const
 {
     return m_NN[0]*m_NN[1];
@@ -365,6 +380,11 @@ inline dim_t Rectangle::getNumFaceElements() const
     return m_faceCount[0] + m_faceCount[1] + m_faceCount[2] + m_faceCount[3];
 }
 
+//protected
+inline index_t Rectangle::getFirstInDim(unsigned axis) const
+{
+    return m_offset[axis] == 0 ? 0 : 1;
+}
 
 } // end of namespace ripley
 
diff --git a/ripley/src/Ripley.h b/ripley/src/Ripley.h
index 910ec2c..4e2a313 100644
--- a/ripley/src/Ripley.h
+++ b/ripley/src/Ripley.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/RipleyDomain.cpp b/ripley/src/RipleyDomain.cpp
index eeaebdc..3b0dc0d 100644
--- a/ripley/src/RipleyDomain.cpp
+++ b/ripley/src/RipleyDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -948,7 +948,8 @@ void RipleyDomain::addToRHS(escript::Data& rhs, const DataMap& coefs,
                     "addPDEToRHS: Ripley does not support contact elements");
 
     if (rhs.isEmpty()) {
-        if (isNotEmpty("X", coefs) || isNotEmpty("Y", coefs))
+        if ((isNotEmpty("X", coefs) && isNotEmpty("du", coefs))
+                || isNotEmpty("Y", coefs))
             throw RipleyException(
                     "addPDEToRHS: right hand side coefficients are provided "
                     "but no right hand side vector given");
@@ -1335,7 +1336,8 @@ void RipleyDomain::assemblePDE(escript::AbstractSystemMatrix* mat,
                                escript::Data& rhs, const DataMap& coefs,
                                Assembler_ptr assembler) const
 {
-    if (rhs.isEmpty() && isNotEmpty("X", coefs) && isNotEmpty("Y", coefs))
+    if (rhs.isEmpty() && (isNotEmpty("X", coefs) || isNotEmpty("du", coefs))
+                && isNotEmpty("Y", coefs))
         throw RipleyException("assemblePDE: right hand side coefficients are "
                     "provided but no right hand side vector given");
 
@@ -1345,7 +1347,7 @@ void RipleyDomain::assemblePDE(escript::AbstractSystemMatrix* mat,
     if (fsTypes.empty()) {
         return;
     }
-
+    
     int fs=fsTypes[0];
     if (fs != Elements && fs != ReducedElements)
         throw RipleyException("assemblePDE: illegal function space type for coefficients");
@@ -1472,6 +1474,7 @@ void RipleyDomain::assemblePDEDirac(escript::AbstractSystemMatrix* mat,
         nComp = mat->getColumnBlockSize();
     }
 
+    rhs.requireWrite();
     for (int i = 0; i < m_diracPoints.size(); i++) { //only for this rank
         const index_t dof = getDofOfNode(m_diracPoints[i].node);
         if (yNotEmpty) {
diff --git a/ripley/src/RipleyDomain.h b/ripley/src/RipleyDomain.h
index 9dd72e8..0352ca3 100644
--- a/ripley/src/RipleyDomain.h
+++ b/ripley/src/RipleyDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -17,16 +17,6 @@
 #ifndef __RIPLEY_DOMAIN_H__
 #define __RIPLEY_DOMAIN_H__
 
-#ifdef BADPYTHONMACROS
-// This hack is required for BSD/OSX builds with python 2.7
-// (and possibly others).  It must be the first include.
-// From bug reports online it seems that python redefines
-// some c macros that are functions in c++.
-// c++ doesn't like that!
-#include <Python.h>
-#undef BADPYTHONMACROS
-#endif
-
 #include <boost/python/tuple.hpp>
 #include <boost/python/list.hpp>
 
@@ -456,10 +446,8 @@ public:
        returns the identifier of the matrix type to be used for the global
        stiffness matrix when a particular solver, package, preconditioner,
        and symmetric matrix is used
-       \param solver
-       \param preconditioner
-       \param package
-       \param symmetry
+       \param options a python object containing the solver, package,
+                preconditioner and symmetry
     */
     virtual int getSystemMatrixTypeId(const boost::python::object& options) const;
 
@@ -712,6 +700,13 @@ public:
 
     /**
        \brief
+       returns a vector of rank numbers where vec[i]=n means that rank n
+       'owns' element/face element i.
+    */
+    virtual RankVector getOwnerVector(int fsType) const = 0;
+
+    /**
+       \brief
        returns true if this domain can handle the specified tuple of filter
        options.
     */
diff --git a/ripley/src/RipleyException.cpp b/ripley/src/RipleyException.cpp
index 588b002..4e18bb1 100644
--- a/ripley/src/RipleyException.cpp
+++ b/ripley/src/RipleyException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/RipleyException.h b/ripley/src/RipleyException.h
index 31f4dd3..b0b5c3e 100644
--- a/ripley/src/RipleyException.h
+++ b/ripley/src/RipleyException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/RipleySystemMatrix.cu b/ripley/src/RipleySystemMatrix.cu
index 8e18ef2..256fcdf 100644
--- a/ripley/src/RipleySystemMatrix.cu
+++ b/ripley/src/RipleySystemMatrix.cu
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/RipleySystemMatrix.h b/ripley/src/RipleySystemMatrix.h
index 83d4639..726f95f 100644
--- a/ripley/src/RipleySystemMatrix.h
+++ b/ripley/src/RipleySystemMatrix.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/SConscript b/ripley/src/SConscript
index 98ef90d..2328f13 100644
--- a/ripley/src/SConscript
+++ b/ripley/src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -35,6 +35,8 @@ sources = """
     domainhelpers.cpp
     LameAssembler2D.cpp
     LameAssembler3D.cpp
+    MultiBrick.cpp
+    MultiRectangle.cpp
     Rectangle.cpp
     RipleyDomain.cpp
     RipleyException.cpp
@@ -51,6 +53,8 @@ headers = """
     domainhelpers.h
     LameAssembler2D.h
     LameAssembler3D.h
+    MultiBrick.h
+    MultiRectangle.h
     Rectangle.h
     Ripley.h
     RipleyDomain.h
diff --git a/ripley/src/WaveAssembler2D.cpp b/ripley/src/WaveAssembler2D.cpp
index 77c2424..becc887 100644
--- a/ripley/src/WaveAssembler2D.cpp
+++ b/ripley/src/WaveAssembler2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,6 +13,11 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <ripley/WaveAssembler2D.h>
 #include <ripley/domainhelpers.h>
 
@@ -52,6 +57,15 @@ WaveAssembler2D::WaveAssembler2D(escript::const_Domain_ptr dom,
     c33 = c.find("c33")->second;
     c44 = c.find("c44")->second;
     c66 = c.find("c66")->second;
+
+    int fs = c11.getFunctionSpace().getTypeCode();
+
+    if (fs != c13.getFunctionSpace().getTypeCode()
+            || fs != c33.getFunctionSpace().getTypeCode()
+            || fs != c44.getFunctionSpace().getTypeCode()
+            || fs != c66.getFunctionSpace().getTypeCode()) {
+        throw RipleyException("C tensor elements are in mismatching function spaces");
+    }
 }
 
 void WaveAssembler2D::collateFunctionSpaceTypes(std::vector<int>& fsTypes,
@@ -84,6 +98,11 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
     const Data& D = unpackData("D", coefs);
     const Data& Y = unpackData("Y", coefs);
     const Data& du = unpackData("du", coefs);
+
+    if ((!du.isEmpty()) && du.getFunctionSpace().getTypeCode() != c11.getFunctionSpace().getTypeCode()) {
+        throw RipleyException("WaveAssembler3D: du and C tensor in mismatching function spaces");
+    }
+
     dim_t numEq, numComp;
     if (!mat)
         numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
@@ -122,24 +141,29 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
     const double w4 = w6*(-SQRT3 + 2);
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
-
+    const bool addEM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool addEM_F = (!du.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
+
 #pragma omp parallel
     {
+        std::vector<double> EM_S(4*4*numEq*numComp, 0);
+        std::vector<double> EM_F(4*numEq, 0);
+
         for (index_t k1_0=0; k1_0<2; k1_0++) { // colouring
 #pragma omp for
             for (index_t k1=k1_0; k1 < NE1; k1+=2) {
                 for (index_t k0=0; k0 < NE0; ++k0)  {
-                    bool addEM_S=false;
-                    bool addEM_F=false;
-                    std::vector<double> EM_S(4*4*numEq*numComp, 0);
-                    std::vector<double> EM_F(4*numEq, 0);
                     const index_t e = k0 + NE0*k1;
+                    if (addEM_S)
+                        fill(EM_S.begin(), EM_S.end(), 0);
+                    if (addEM_F)
+                        fill(EM_F.begin(), EM_F.end(), 0);
+
                     ///////////////
                     // process A //
                     ///////////////
                     if (!A.isEmpty()) {
-                        addEM_S = true;
                         const double* A_p = A.getSampleDataRO(e);
                         if (A.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -269,7 +293,6 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                     // process B //
                     ///////////////
                     if (!B.isEmpty()) {
-                        addEM_S=true;
                         const double* B_p=B.getSampleDataRO(e);
                         if (B.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -345,7 +368,6 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                     // process C //
                     ///////////////
                     if (!C.isEmpty()) {
-                        addEM_S=true;
                         const double* C_p=C.getSampleDataRO(e);
                         if (C.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -421,7 +443,6 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                     // process D //
                     ///////////////
                     if (!D.isEmpty()) {
-                        addEM_S=true;
                         const double* D_p=D.getSampleDataRO(e);
                         if (D.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
@@ -483,11 +504,10 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                             }
                         }
                     }
-                    ///////////////
-                    // process X //
-                    ///////////////
+                    ////////////////
+                    // process du //
+                    ////////////////
                     if (!du.isEmpty()) {
-                        addEM_F=true;
                         const double *du_p = du.getSampleDataRO(e);
                         const double *c11_p = c11.getSampleDataRO(e);
                         const double *c13_p = c13.getSampleDataRO(e);
@@ -502,21 +522,21 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
 
                             if (isVTI) {
                                 const double *c44_p = c44.getSampleDataRO(e);
-                                X_00_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c11_p[0] 
+                                X_00_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c11_p[0]
                                         + du_p[INDEX3(1,1,0,numEq,2)] * c13_p[0]);
-                                X_00_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c11_p[1] 
+                                X_00_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c11_p[1]
                                         + du_p[INDEX3(1,1,1,numEq,2)] * c13_p[1]);
-                                X_00_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c11_p[2] 
+                                X_00_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c11_p[2]
                                         + du_p[INDEX3(1,1,2,numEq,2)] * c13_p[2]);
-                                X_00_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c11_p[3] 
+                                X_00_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c11_p[3]
                                         + du_p[INDEX3(1,1,3,numEq,2)] * c13_p[3]);
-                                X_11_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c13_p[0] 
+                                X_11_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c13_p[0]
                                         + du_p[INDEX3(1,1,0,numEq,2)] * c33_p[0]);
-                                X_11_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c13_p[1] 
+                                X_11_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c13_p[1]
                                         + du_p[INDEX3(1,1,1,numEq,2)] * c33_p[1]);
-                                X_11_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c13_p[2] 
+                                X_11_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c13_p[2]
                                         + du_p[INDEX3(1,1,2,numEq,2)] * c33_p[2]);
-                                X_11_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c13_p[3] 
+                                X_11_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c13_p[3]
                                         + du_p[INDEX3(1,1,3,numEq,2)] * c33_p[3]);
                                 X_01_0 *= c44_p[0];
                                 X_01_1 *= c44_p[1];
@@ -524,21 +544,21 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                                 X_01_3 *= c44_p[3];
                             } else { // isHTI
                                 const double *c66_p = c66.getSampleDataRO(e);
-                                X_00_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c11_p[0] 
+                                X_00_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c11_p[0]
                                         + du_p[INDEX3(1,1,0,numEq,2)] * c13_p[0]);
-                                X_00_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c11_p[1] 
+                                X_00_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c11_p[1]
                                         + du_p[INDEX3(1,1,1,numEq,2)] * c13_p[1]);
-                                X_00_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c11_p[2] 
+                                X_00_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c11_p[2]
                                         + du_p[INDEX3(1,1,2,numEq,2)] * c13_p[2]);
-                                X_00_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c11_p[3] 
+                                X_00_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c11_p[3]
                                         + du_p[INDEX3(1,1,3,numEq,2)] * c13_p[3]);
-                                X_11_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c13_p[0] 
+                                X_11_0 = -(du_p[INDEX3(0,0,0,numEq,2)] * c13_p[0]
                                         + du_p[INDEX3(1,1,0,numEq,2)] * c33_p[0]);
-                                X_11_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c13_p[1] 
+                                X_11_1 = -(du_p[INDEX3(0,0,1,numEq,2)] * c13_p[1]
                                         + du_p[INDEX3(1,1,1,numEq,2)] * c33_p[1]);
-                                X_11_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c13_p[2] 
+                                X_11_2 = -(du_p[INDEX3(0,0,2,numEq,2)] * c13_p[2]
                                         + du_p[INDEX3(1,1,2,numEq,2)] * c33_p[2]);
-                                X_11_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c13_p[3] 
+                                X_11_3 = -(du_p[INDEX3(0,0,3,numEq,2)] * c13_p[3]
                                         + du_p[INDEX3(1,1,3,numEq,2)] * c33_p[3]);
                                 X_01_0 *= c66_p[0];
                                 X_01_1 *= c66_p[1];
@@ -566,10 +586,6 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                             const double Atmp13 = w28*(X_01_0 + X_01_2);
                             const double Atmp14 = w25*(X_00_2 + X_00_3);
                             const double Atmp15 = w26*(X_00_0 + X_00_1);
-                            EM_F[INDEX2(0,0,numEq)]+=Atmp0 + Atmp1 + Atmp2 + Atmp3;
-                            EM_F[INDEX2(0,1,numEq)]+=Atmp4 + Atmp5 + Atmp6 + Atmp7;
-                            EM_F[INDEX2(0,2,numEq)]+=Atmp10 + Atmp11 + Atmp8 + Atmp9;
-                            EM_F[INDEX2(0,3,numEq)]+=Atmp12 + Atmp13 + Atmp14 + Atmp15;
                             const double Btmp0 = 6*w15*(X_10_2 + X_10_3);
                             const double Btmp1 = 6*w10*(X_10_0 + X_10_1);
                             const double Btmp2 = 6*w11*(X_11_0 + X_11_2);
@@ -586,41 +602,45 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                             const double Btmp13 = w28*(X_11_0 + X_11_2);
                             const double Btmp14 = w25*(X_10_2 + X_10_3);
                             const double Btmp15 = w26*(X_10_0 + X_10_1);
+                            EM_F[INDEX2(0,0,numEq)]+=Atmp0 + Atmp1 + Atmp2 + Atmp3;
                             EM_F[INDEX2(1,0,numEq)]+=Btmp0 + Btmp1 + Btmp2 + Btmp3;
+                            EM_F[INDEX2(0,1,numEq)]+=Atmp4 + Atmp5 + Atmp6 + Atmp7;
                             EM_F[INDEX2(1,1,numEq)]+=Btmp4 + Btmp5 + Btmp6 + Btmp7;
+                            EM_F[INDEX2(0,2,numEq)]+=Atmp10 + Atmp11 + Atmp8 + Atmp9;
                             EM_F[INDEX2(1,2,numEq)]+=Btmp10 + Btmp11 + Btmp8 + Btmp9;
+                            EM_F[INDEX2(0,3,numEq)]+=Atmp12 + Atmp13 + Atmp14 + Atmp15;
                             EM_F[INDEX2(1,3,numEq)]+=Btmp12 + Btmp13 + Btmp14 + Btmp15;
 
                         } else { // constant data
                             double wX_00, wX_01, wX_10, wX_11;
                             if (isVTI) {
                                 const double *c44_p = c44.getSampleDataRO(e);
-                                wX_00 = -(du_p[INDEX2(0,0,numEq)] * c11_p[0] 
+                                wX_00 = -(du_p[INDEX2(0,0,numEq)] * c11_p[0]
                                                     + du_p[INDEX2(1,1,numEq)] * c13_p[0])*w18;
                                 wX_01 = -(c44_p[0] *
                                                     (du_p[INDEX2(1,0,numEq)] + du_p[INDEX2(0,1,numEq)]))*w19;
                                 wX_10 = -(c44_p[0] *
                                                     (du_p[INDEX2(1,0,numEq)] + du_p[INDEX2(0,1,numEq)]))*w18;
-                                wX_11 = -(du_p[INDEX2(0,0,numEq)] * c13_p[0] 
+                                wX_11 = -(du_p[INDEX2(0,0,numEq)] * c13_p[0]
                                                     + du_p[INDEX2(1,1,numEq)] * c33_p[0])*w19;
-                            } else { // isHTI 
+                            } else { // isHTI
                                 const double *c66_p = c66.getSampleDataRO(e);
-                                wX_00 = -(du_p[INDEX2(0,0,numEq)] * c11_p[0] 
+                                wX_00 = -(du_p[INDEX2(0,0,numEq)] * c11_p[0]
                                         + du_p[INDEX2(1,1,numEq)] * c13_p[0])*w18;
                                 wX_01 = -(c66_p[0] *
                                                     (du_p[INDEX2(1,0,numEq)] + du_p[INDEX2(0,1,numEq)]))*w19;
                                 wX_10 = -(c66_p[0] *
                                                     (du_p[INDEX2(1,0,numEq)] + du_p[INDEX2(0,1,numEq)]))*w18;
-                                wX_11 = -(du_p[INDEX2(0,0,numEq)] * c13_p[0] 
+                                wX_11 = -(du_p[INDEX2(0,0,numEq)] * c13_p[0]
                                         + du_p[INDEX2(1,1,numEq)] * c33_p[0])*w19;
                             }
                             EM_F[INDEX2(0,0,numEq)]+= wX_00 + wX_01;
-                            EM_F[INDEX2(0,1,numEq)]+=-wX_00 + wX_01;
-                            EM_F[INDEX2(0,2,numEq)]+= wX_00 - wX_01;
-                            EM_F[INDEX2(0,3,numEq)]+=-wX_00 - wX_01;
                             EM_F[INDEX2(1,0,numEq)]+= wX_10 + wX_11;
+                            EM_F[INDEX2(0,1,numEq)]+=-wX_00 + wX_01;
                             EM_F[INDEX2(1,1,numEq)]+=-wX_10 + wX_11;
+                            EM_F[INDEX2(0,2,numEq)]+= wX_00 - wX_01;
                             EM_F[INDEX2(1,2,numEq)]+= wX_10 - wX_11;
+                            EM_F[INDEX2(0,3,numEq)]+=-wX_00 - wX_01;
                             EM_F[INDEX2(1,3,numEq)]+=-wX_10 - wX_11;
                         }
                     }
@@ -628,7 +648,6 @@ void WaveAssembler2D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                     // process Y //
                     ///////////////
                     if (!Y.isEmpty()) {
-                        addEM_F=true;
                         const double* Y_p=Y.getSampleDataRO(e);
                         if (Y.actsExpanded()) {
                             for (index_t k=0; k<numEq; k++) {
diff --git a/ripley/src/WaveAssembler2D.h b/ripley/src/WaveAssembler2D.h
index 0ef2916..65d0531 100644
--- a/ripley/src/WaveAssembler2D.h
+++ b/ripley/src/WaveAssembler2D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -36,31 +36,31 @@ public:
 
     void assemblePDESingle(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDESingle() not supported by this assembler");
     }
     void assemblePDEBoundarySingle(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySingle() not supported by this assembler");
     }
     void assemblePDESingleReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDESingleReduced() not supported by this assembler");
     }
     void assemblePDEBoundarySingleReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySingleReduced() not supported by this assembler");
     }
     void assemblePDEBoundarySystem(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySystem() not supported by this assembler");
     }
     void assemblePDESystemReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDESystemReduced() not supported by this assembler");
     }
     void assemblePDEBoundarySystemReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySystemReduced() not supported by this assembler");
     }
 
     void collateFunctionSpaceTypes(std::vector<int>& fsTypes,
diff --git a/ripley/src/WaveAssembler3D.cpp b/ripley/src/WaveAssembler3D.cpp
index 25a23d1..7825a5a 100644
--- a/ripley/src/WaveAssembler3D.cpp
+++ b/ripley/src/WaveAssembler3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,6 +13,11 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <ripley/WaveAssembler3D.h>
 #include <ripley/domainhelpers.h>
 
@@ -36,7 +41,7 @@ WaveAssembler3D::WaveAssembler3D(escript::const_Domain_ptr dom,
                 || c.find("c44") == c.end() || c.find("c66") == c.end()
                 || (a == c.end() && b == c.end()))
         throw RipleyException("required constants missing for WaveAssembler");
-        
+
     if (a != c.end() && b != c.end()) {
         throw RipleyException("WaveAssembler3D() doesn't support general "
                               "form waves (yet)");
@@ -52,9 +57,18 @@ WaveAssembler3D::WaveAssembler3D(escript::const_Domain_ptr dom,
     c33 = c.find("c33")->second,
     c44 = c.find("c44")->second;
     c66 = c.find("c66")->second;
+
+    int fs = c11.getFunctionSpace().getTypeCode();
+
+    if (fs != c13.getFunctionSpace().getTypeCode()
+            || fs != c33.getFunctionSpace().getTypeCode()
+            || fs != c44.getFunctionSpace().getTypeCode()
+            || fs != c66.getFunctionSpace().getTypeCode()) {
+        throw RipleyException("C tensor elements are in mismatching function spaces");
+    }
 }
 
-void WaveAssembler3D::collateFunctionSpaceTypes(std::vector<int>& fsTypes, 
+void WaveAssembler3D::collateFunctionSpaceTypes(std::vector<int>& fsTypes,
                                                 const DataMap& coefs) const
 {
     if (isNotEmpty("A", coefs))
@@ -85,6 +99,11 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
     const Data& D = unpackData("D", coefs);
     const Data& Y = unpackData("Y", coefs);
     const Data& du = unpackData("du", coefs);
+
+    if ((!du.isEmpty()) && du.getFunctionSpace().getTypeCode() != c11.getFunctionSpace().getTypeCode()) {
+        throw RipleyException("WaveAssembler3D: du and C tensor in mismatching function spaces");
+    }
+
     dim_t numEq, numComp;
     if (!mat)
         numEq=numComp=(rhs.isEmpty() ? 1 : rhs.getDataPointSize());
@@ -168,25 +187,30 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
     const int NE0 = m_NE[0];
     const int NE1 = m_NE[1];
     const int NE2 = m_NE[2];
-
+    const bool add_EM_S = (!A.isEmpty() || !B.isEmpty() || !C.isEmpty() || !D.isEmpty());
+    const bool add_EM_F = (!du.isEmpty() || !Y.isEmpty());
     rhs.requireWrite();
+
 #pragma omp parallel
     {
+        std::vector<double> EM_S(8*8*numEq*numComp, 0);
+        std::vector<double> EM_F(8*numEq, 0);
+
         for (index_t k2_0=0; k2_0<2; k2_0++) { // colouring
 #pragma omp for
             for (index_t k2=k2_0; k2<NE2; k2+=2) {
                 for (index_t k1=0; k1<NE1; ++k1) {
                     for (index_t k0=0; k0<NE0; ++k0)  {
-                        bool add_EM_S=false;
-                        bool add_EM_F=false;
-                        std::vector<double> EM_S(8*8*numEq*numComp, 0);
-                        std::vector<double> EM_F(8*numEq, 0);
                         const index_t e = k0 + NE0*k1 + NE0*NE1*k2;
+                        if (add_EM_S)
+                            fill(EM_S.begin(), EM_S.end(), 0);
+                        if (add_EM_F)
+                            fill(EM_F.begin(), EM_F.end(), 0);
+
                         ///////////////
                         // process A //
                         ///////////////
                         if (!A.isEmpty()) {
-                            add_EM_S = true;
                             const double* A_p = A.getSampleDataRO(e);
                             if (A.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -929,7 +953,6 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                         // process B //
                         ///////////////
                         if (!B.isEmpty()) {
-                            add_EM_S=true;
                             const double* B_p=B.getSampleDataRO(e);
                             if (B.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -1366,7 +1389,6 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                         // process C //
                         ///////////////
                         if (!C.isEmpty()) {
-                            add_EM_S=true;
                             const double* C_p=C.getSampleDataRO(e);
                             if (C.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -1803,7 +1825,6 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                         // process D //
                         ///////////////
                         if (!D.isEmpty()) {
-                            add_EM_S=true;
                             const double* D_p=D.getSampleDataRO(e);
                             if (D.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
@@ -2017,7 +2038,6 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                         // process X //
                         ///////////////
                         if (!du.isEmpty()) {
-                            add_EM_F=true;
                             const double *du_p = du.getSampleDataRO(e);
                             const double *c11_p = c11.getSampleDataRO(e),
                                          *c13_p = c13.getSampleDataRO(e),
@@ -2025,23 +2045,23 @@ void WaveAssembler3D::assemblePDESystem(escript::AbstractSystemMatrix* mat,
                                          *c44_p = c44.getSampleDataRO(e),
                                          *c66_p = c66.getSampleDataRO(e);
                             if (du.actsExpanded()) {
-const double X_01_0 = -(c66_p[0]*(du_p[INDEX3(0,1,0,numEq,3)]+du_p[INDEX3(1,0,0,numEq,3)]));
-const double X_01_1 = -(c66_p[1]*(du_p[INDEX3(0,1,1,numEq,3)]+du_p[INDEX3(1,0,1,numEq,3)]));
-const double X_01_2 = -(c66_p[2]*(du_p[INDEX3(0,1,2,numEq,3)]+du_p[INDEX3(1,0,2,numEq,3)]));
-const double X_01_3 = -(c66_p[3]*(du_p[INDEX3(0,1,3,numEq,3)]+du_p[INDEX3(1,0,3,numEq,3)]));
-const double X_01_4 = -(c66_p[4]*(du_p[INDEX3(0,1,4,numEq,3)]+du_p[INDEX3(1,0,4,numEq,3)]));
-const double X_01_5 = -(c66_p[5]*(du_p[INDEX3(0,1,5,numEq,3)]+du_p[INDEX3(1,0,5,numEq,3)]));
-const double X_01_6 = -(c66_p[6]*(du_p[INDEX3(0,1,6,numEq,3)]+du_p[INDEX3(1,0,6,numEq,3)]));
-const double X_01_7 = -(c66_p[7]*(du_p[INDEX3(0,1,7,numEq,3)]+du_p[INDEX3(1,0,7,numEq,3)]));
-const double X_12_0 = -(c44_p[0]*(du_p[INDEX3(2,1,0,numEq,3)]+du_p[INDEX3(1,2,0,numEq,3)]));
-const double X_12_1 = -(c44_p[1]*(du_p[INDEX3(2,1,1,numEq,3)]+du_p[INDEX3(1,2,1,numEq,3)]));
-const double X_12_2 = -(c44_p[2]*(du_p[INDEX3(2,1,2,numEq,3)]+du_p[INDEX3(1,2,2,numEq,3)]));
-const double X_12_3 = -(c44_p[3]*(du_p[INDEX3(2,1,3,numEq,3)]+du_p[INDEX3(1,2,3,numEq,3)]));
-const double X_12_4 = -(c44_p[4]*(du_p[INDEX3(2,1,4,numEq,3)]+du_p[INDEX3(1,2,4,numEq,3)]));
-const double X_12_5 = -(c44_p[5]*(du_p[INDEX3(2,1,5,numEq,3)]+du_p[INDEX3(1,2,5,numEq,3)]));
-const double X_12_6 = -(c44_p[6]*(du_p[INDEX3(2,1,6,numEq,3)]+du_p[INDEX3(1,2,6,numEq,3)]));
-const double X_12_7 = -(c44_p[7]*(du_p[INDEX3(2,1,7,numEq,3)]+du_p[INDEX3(1,2,7,numEq,3)]));
-                                double X_00_0, X_00_1, X_00_2, X_00_3, 
+                                const double X_01_0 = -(c66_p[0]*(du_p[INDEX3(0,1,0,numEq,3)]+du_p[INDEX3(1,0,0,numEq,3)]));
+                                const double X_01_1 = -(c66_p[1]*(du_p[INDEX3(0,1,1,numEq,3)]+du_p[INDEX3(1,0,1,numEq,3)]));
+                                const double X_01_2 = -(c66_p[2]*(du_p[INDEX3(0,1,2,numEq,3)]+du_p[INDEX3(1,0,2,numEq,3)]));
+                                const double X_01_3 = -(c66_p[3]*(du_p[INDEX3(0,1,3,numEq,3)]+du_p[INDEX3(1,0,3,numEq,3)]));
+                                const double X_01_4 = -(c66_p[4]*(du_p[INDEX3(0,1,4,numEq,3)]+du_p[INDEX3(1,0,4,numEq,3)]));
+                                const double X_01_5 = -(c66_p[5]*(du_p[INDEX3(0,1,5,numEq,3)]+du_p[INDEX3(1,0,5,numEq,3)]));
+                                const double X_01_6 = -(c66_p[6]*(du_p[INDEX3(0,1,6,numEq,3)]+du_p[INDEX3(1,0,6,numEq,3)]));
+                                const double X_01_7 = -(c66_p[7]*(du_p[INDEX3(0,1,7,numEq,3)]+du_p[INDEX3(1,0,7,numEq,3)]));
+                                const double X_12_0 = -(c44_p[0]*(du_p[INDEX3(2,1,0,numEq,3)]+du_p[INDEX3(1,2,0,numEq,3)]));
+                                const double X_12_1 = -(c44_p[1]*(du_p[INDEX3(2,1,1,numEq,3)]+du_p[INDEX3(1,2,1,numEq,3)]));
+                                const double X_12_2 = -(c44_p[2]*(du_p[INDEX3(2,1,2,numEq,3)]+du_p[INDEX3(1,2,2,numEq,3)]));
+                                const double X_12_3 = -(c44_p[3]*(du_p[INDEX3(2,1,3,numEq,3)]+du_p[INDEX3(1,2,3,numEq,3)]));
+                                const double X_12_4 = -(c44_p[4]*(du_p[INDEX3(2,1,4,numEq,3)]+du_p[INDEX3(1,2,4,numEq,3)]));
+                                const double X_12_5 = -(c44_p[5]*(du_p[INDEX3(2,1,5,numEq,3)]+du_p[INDEX3(1,2,5,numEq,3)]));
+                                const double X_12_6 = -(c44_p[6]*(du_p[INDEX3(2,1,6,numEq,3)]+du_p[INDEX3(1,2,6,numEq,3)]));
+                                const double X_12_7 = -(c44_p[7]*(du_p[INDEX3(2,1,7,numEq,3)]+du_p[INDEX3(1,2,7,numEq,3)]));
+                                double X_00_0, X_00_1, X_00_2, X_00_3,
                                        X_00_4, X_00_5, X_00_6, X_00_7,
                                        X_02_0, X_02_1, X_02_2, X_02_3,
                                        X_02_4, X_02_5, X_02_6, X_02_7,
@@ -2051,284 +2071,284 @@ const double X_12_7 = -(c44_p[7]*(du_p[INDEX3(2,1,7,numEq,3)]+du_p[INDEX3(1,2,7,
                                        X_22_4, X_22_5, X_22_6, X_22_7;
                                 if (isVTI) {
                                     const double *c12_p = c12.getSampleDataRO(e);
-X_00_0 = -(c11_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c12_p[0]*du_p[INDEX3(1,1,0,numEq,3)]+c13_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
-X_00_1 = -(c11_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c12_p[1]*du_p[INDEX3(1,1,1,numEq,3)]+c13_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
-X_00_2 = -(c11_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c12_p[2]*du_p[INDEX3(1,1,2,numEq,3)]+c13_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
-X_00_3 = -(c11_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c12_p[3]*du_p[INDEX3(1,1,3,numEq,3)]+c13_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
-X_00_4 = -(c11_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c12_p[4]*du_p[INDEX3(1,1,4,numEq,3)]+c13_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
-X_00_5 = -(c11_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c12_p[5]*du_p[INDEX3(1,1,5,numEq,3)]+c13_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
-X_00_6 = -(c11_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c12_p[6]*du_p[INDEX3(1,1,6,numEq,3)]+c13_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
-X_00_7 = -(c11_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c12_p[7]*du_p[INDEX3(1,1,7,numEq,3)]+c13_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
+                                    X_00_0 = -(c11_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c12_p[0]*du_p[INDEX3(1,1,0,numEq,3)]+c13_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
+                                    X_00_1 = -(c11_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c12_p[1]*du_p[INDEX3(1,1,1,numEq,3)]+c13_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
+                                    X_00_2 = -(c11_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c12_p[2]*du_p[INDEX3(1,1,2,numEq,3)]+c13_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
+                                    X_00_3 = -(c11_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c12_p[3]*du_p[INDEX3(1,1,3,numEq,3)]+c13_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
+                                    X_00_4 = -(c11_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c12_p[4]*du_p[INDEX3(1,1,4,numEq,3)]+c13_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
+                                    X_00_5 = -(c11_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c12_p[5]*du_p[INDEX3(1,1,5,numEq,3)]+c13_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
+                                    X_00_6 = -(c11_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c12_p[6]*du_p[INDEX3(1,1,6,numEq,3)]+c13_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
+                                    X_00_7 = -(c11_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c12_p[7]*du_p[INDEX3(1,1,7,numEq,3)]+c13_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
 
-X_02_0 = -(c44_p[0]*(du_p[INDEX3(2,0,0,numEq,3)]+du_p[INDEX3(0,2,0,numEq,3)]));
-X_02_1 = -(c44_p[1]*(du_p[INDEX3(2,0,1,numEq,3)]+du_p[INDEX3(0,2,1,numEq,3)]));
-X_02_2 = -(c44_p[2]*(du_p[INDEX3(2,0,2,numEq,3)]+du_p[INDEX3(0,2,2,numEq,3)]));
-X_02_3 = -(c44_p[3]*(du_p[INDEX3(2,0,3,numEq,3)]+du_p[INDEX3(0,2,3,numEq,3)]));
-X_02_4 = -(c44_p[4]*(du_p[INDEX3(2,0,4,numEq,3)]+du_p[INDEX3(0,2,4,numEq,3)]));
-X_02_5 = -(c44_p[5]*(du_p[INDEX3(2,0,5,numEq,3)]+du_p[INDEX3(0,2,5,numEq,3)]));
-X_02_6 = -(c44_p[6]*(du_p[INDEX3(2,0,6,numEq,3)]+du_p[INDEX3(0,2,6,numEq,3)]));
-X_02_7 = -(c44_p[7]*(du_p[INDEX3(2,0,7,numEq,3)]+du_p[INDEX3(0,2,7,numEq,3)]));
+                                    X_02_0 = -(c44_p[0]*(du_p[INDEX3(2,0,0,numEq,3)]+du_p[INDEX3(0,2,0,numEq,3)]));
+                                    X_02_1 = -(c44_p[1]*(du_p[INDEX3(2,0,1,numEq,3)]+du_p[INDEX3(0,2,1,numEq,3)]));
+                                    X_02_2 = -(c44_p[2]*(du_p[INDEX3(2,0,2,numEq,3)]+du_p[INDEX3(0,2,2,numEq,3)]));
+                                    X_02_3 = -(c44_p[3]*(du_p[INDEX3(2,0,3,numEq,3)]+du_p[INDEX3(0,2,3,numEq,3)]));
+                                    X_02_4 = -(c44_p[4]*(du_p[INDEX3(2,0,4,numEq,3)]+du_p[INDEX3(0,2,4,numEq,3)]));
+                                    X_02_5 = -(c44_p[5]*(du_p[INDEX3(2,0,5,numEq,3)]+du_p[INDEX3(0,2,5,numEq,3)]));
+                                    X_02_6 = -(c44_p[6]*(du_p[INDEX3(2,0,6,numEq,3)]+du_p[INDEX3(0,2,6,numEq,3)]));
+                                    X_02_7 = -(c44_p[7]*(du_p[INDEX3(2,0,7,numEq,3)]+du_p[INDEX3(0,2,7,numEq,3)]));
 
-X_11_0 = -(c12_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c11_p[0]*du_p[INDEX3(1,1,0,numEq,3)]+c13_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
-X_11_1 = -(c12_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c11_p[1]*du_p[INDEX3(1,1,1,numEq,3)]+c13_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
-X_11_2 = -(c12_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c11_p[2]*du_p[INDEX3(1,1,2,numEq,3)]+c13_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
-X_11_3 = -(c12_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c11_p[3]*du_p[INDEX3(1,1,3,numEq,3)]+c13_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
-X_11_4 = -(c12_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c11_p[4]*du_p[INDEX3(1,1,4,numEq,3)]+c13_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
-X_11_5 = -(c12_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c11_p[5]*du_p[INDEX3(1,1,5,numEq,3)]+c13_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
-X_11_6 = -(c12_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c11_p[6]*du_p[INDEX3(1,1,6,numEq,3)]+c13_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
-X_11_7 = -(c12_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c11_p[7]*du_p[INDEX3(1,1,7,numEq,3)]+c13_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
+                                    X_11_0 = -(c12_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c11_p[0]*du_p[INDEX3(1,1,0,numEq,3)]+c13_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
+                                    X_11_1 = -(c12_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c11_p[1]*du_p[INDEX3(1,1,1,numEq,3)]+c13_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
+                                    X_11_2 = -(c12_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c11_p[2]*du_p[INDEX3(1,1,2,numEq,3)]+c13_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
+                                    X_11_3 = -(c12_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c11_p[3]*du_p[INDEX3(1,1,3,numEq,3)]+c13_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
+                                    X_11_4 = -(c12_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c11_p[4]*du_p[INDEX3(1,1,4,numEq,3)]+c13_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
+                                    X_11_5 = -(c12_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c11_p[5]*du_p[INDEX3(1,1,5,numEq,3)]+c13_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
+                                    X_11_6 = -(c12_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c11_p[6]*du_p[INDEX3(1,1,6,numEq,3)]+c13_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
+                                    X_11_7 = -(c12_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c11_p[7]*du_p[INDEX3(1,1,7,numEq,3)]+c13_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
 
-X_22_0 = -(c13_p[0]*(du_p[INDEX3(0,0,0,numEq,3)] + du_p[INDEX3(1,1,0,numEq,3)]) + c33_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
-X_22_1 = -(c13_p[1]*(du_p[INDEX3(0,0,1,numEq,3)] + du_p[INDEX3(1,1,1,numEq,3)]) + c33_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
-X_22_2 = -(c13_p[2]*(du_p[INDEX3(0,0,2,numEq,3)] + du_p[INDEX3(1,1,2,numEq,3)]) + c33_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
-X_22_3 = -(c13_p[3]*(du_p[INDEX3(0,0,3,numEq,3)] + du_p[INDEX3(1,1,3,numEq,3)]) + c33_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
-X_22_4 = -(c13_p[4]*(du_p[INDEX3(0,0,4,numEq,3)] + du_p[INDEX3(1,1,4,numEq,3)]) + c33_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
-X_22_5 = -(c13_p[5]*(du_p[INDEX3(0,0,5,numEq,3)] + du_p[INDEX3(1,1,5,numEq,3)]) + c33_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
-X_22_6 = -(c13_p[6]*(du_p[INDEX3(0,0,6,numEq,3)] + du_p[INDEX3(1,1,6,numEq,3)]) + c33_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
-X_22_7 = -(c13_p[7]*(du_p[INDEX3(0,0,7,numEq,3)] + du_p[INDEX3(1,1,7,numEq,3)]) + c33_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
+                                    X_22_0 = -(c13_p[0]*(du_p[INDEX3(0,0,0,numEq,3)] + du_p[INDEX3(1,1,0,numEq,3)]) + c33_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
+                                    X_22_1 = -(c13_p[1]*(du_p[INDEX3(0,0,1,numEq,3)] + du_p[INDEX3(1,1,1,numEq,3)]) + c33_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
+                                    X_22_2 = -(c13_p[2]*(du_p[INDEX3(0,0,2,numEq,3)] + du_p[INDEX3(1,1,2,numEq,3)]) + c33_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
+                                    X_22_3 = -(c13_p[3]*(du_p[INDEX3(0,0,3,numEq,3)] + du_p[INDEX3(1,1,3,numEq,3)]) + c33_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
+                                    X_22_4 = -(c13_p[4]*(du_p[INDEX3(0,0,4,numEq,3)] + du_p[INDEX3(1,1,4,numEq,3)]) + c33_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
+                                    X_22_5 = -(c13_p[5]*(du_p[INDEX3(0,0,5,numEq,3)] + du_p[INDEX3(1,1,5,numEq,3)]) + c33_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
+                                    X_22_6 = -(c13_p[6]*(du_p[INDEX3(0,0,6,numEq,3)] + du_p[INDEX3(1,1,6,numEq,3)]) + c33_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
+                                    X_22_7 = -(c13_p[7]*(du_p[INDEX3(0,0,7,numEq,3)] + du_p[INDEX3(1,1,7,numEq,3)]) + c33_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
                                 } else { // isHTI
                                     const double *c23_p = c23.getSampleDataRO(e);
-X_00_0 = -(c11_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c13_p[0]*(du_p[INDEX3(1,1,0,numEq,3)]+du_p[INDEX3(2,2,0,numEq,3)]));
-X_00_1 = -(c11_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c13_p[1]*(du_p[INDEX3(1,1,1,numEq,3)]+du_p[INDEX3(2,2,1,numEq,3)]));
-X_00_2 = -(c11_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c13_p[2]*(du_p[INDEX3(1,1,2,numEq,3)]+du_p[INDEX3(2,2,2,numEq,3)]));
-X_00_3 = -(c11_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c13_p[3]*(du_p[INDEX3(1,1,3,numEq,3)]+du_p[INDEX3(2,2,3,numEq,3)]));
-X_00_4 = -(c11_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c13_p[4]*(du_p[INDEX3(1,1,4,numEq,3)]+du_p[INDEX3(2,2,4,numEq,3)]));
-X_00_5 = -(c11_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c13_p[5]*(du_p[INDEX3(1,1,5,numEq,3)]+du_p[INDEX3(2,2,5,numEq,3)]));
-X_00_6 = -(c11_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c13_p[6]*(du_p[INDEX3(1,1,6,numEq,3)]+du_p[INDEX3(2,2,6,numEq,3)]));
-X_00_7 = -(c11_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c13_p[7]*(du_p[INDEX3(1,1,7,numEq,3)]+du_p[INDEX3(2,2,7,numEq,3)]));
+                                    X_00_0 = -(c11_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c13_p[0]*(du_p[INDEX3(1,1,0,numEq,3)]+du_p[INDEX3(2,2,0,numEq,3)]));
+                                    X_00_1 = -(c11_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c13_p[1]*(du_p[INDEX3(1,1,1,numEq,3)]+du_p[INDEX3(2,2,1,numEq,3)]));
+                                    X_00_2 = -(c11_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c13_p[2]*(du_p[INDEX3(1,1,2,numEq,3)]+du_p[INDEX3(2,2,2,numEq,3)]));
+                                    X_00_3 = -(c11_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c13_p[3]*(du_p[INDEX3(1,1,3,numEq,3)]+du_p[INDEX3(2,2,3,numEq,3)]));
+                                    X_00_4 = -(c11_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c13_p[4]*(du_p[INDEX3(1,1,4,numEq,3)]+du_p[INDEX3(2,2,4,numEq,3)]));
+                                    X_00_5 = -(c11_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c13_p[5]*(du_p[INDEX3(1,1,5,numEq,3)]+du_p[INDEX3(2,2,5,numEq,3)]));
+                                    X_00_6 = -(c11_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c13_p[6]*(du_p[INDEX3(1,1,6,numEq,3)]+du_p[INDEX3(2,2,6,numEq,3)]));
+                                    X_00_7 = -(c11_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c13_p[7]*(du_p[INDEX3(1,1,7,numEq,3)]+du_p[INDEX3(2,2,7,numEq,3)]));
 
-X_02_0 = -(c66_p[0]*(du_p[INDEX3(2,0,0,numEq,3)]+du_p[INDEX3(0,2,0,numEq,3)]));
-X_02_1 = -(c66_p[1]*(du_p[INDEX3(2,0,1,numEq,3)]+du_p[INDEX3(0,2,1,numEq,3)]));
-X_02_2 = -(c66_p[2]*(du_p[INDEX3(2,0,2,numEq,3)]+du_p[INDEX3(0,2,2,numEq,3)]));
-X_02_3 = -(c66_p[3]*(du_p[INDEX3(2,0,3,numEq,3)]+du_p[INDEX3(0,2,3,numEq,3)]));
-X_02_4 = -(c66_p[4]*(du_p[INDEX3(2,0,4,numEq,3)]+du_p[INDEX3(0,2,4,numEq,3)]));
-X_02_5 = -(c66_p[5]*(du_p[INDEX3(2,0,5,numEq,3)]+du_p[INDEX3(0,2,5,numEq,3)]));
-X_02_6 = -(c66_p[6]*(du_p[INDEX3(2,0,6,numEq,3)]+du_p[INDEX3(0,2,6,numEq,3)]));
-X_02_7 = -(c66_p[7]*(du_p[INDEX3(2,0,7,numEq,3)]+du_p[INDEX3(0,2,7,numEq,3)]));
+                                    X_02_0 = -(c66_p[0]*(du_p[INDEX3(2,0,0,numEq,3)]+du_p[INDEX3(0,2,0,numEq,3)]));
+                                    X_02_1 = -(c66_p[1]*(du_p[INDEX3(2,0,1,numEq,3)]+du_p[INDEX3(0,2,1,numEq,3)]));
+                                    X_02_2 = -(c66_p[2]*(du_p[INDEX3(2,0,2,numEq,3)]+du_p[INDEX3(0,2,2,numEq,3)]));
+                                    X_02_3 = -(c66_p[3]*(du_p[INDEX3(2,0,3,numEq,3)]+du_p[INDEX3(0,2,3,numEq,3)]));
+                                    X_02_4 = -(c66_p[4]*(du_p[INDEX3(2,0,4,numEq,3)]+du_p[INDEX3(0,2,4,numEq,3)]));
+                                    X_02_5 = -(c66_p[5]*(du_p[INDEX3(2,0,5,numEq,3)]+du_p[INDEX3(0,2,5,numEq,3)]));
+                                    X_02_6 = -(c66_p[6]*(du_p[INDEX3(2,0,6,numEq,3)]+du_p[INDEX3(0,2,6,numEq,3)]));
+                                    X_02_7 = -(c66_p[7]*(du_p[INDEX3(2,0,7,numEq,3)]+du_p[INDEX3(0,2,7,numEq,3)]));
 
-X_11_0 = -(c13_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c33_p[0]*du_p[INDEX3(1,1,0,numEq,3)]+c23_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
-X_11_1 = -(c13_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c33_p[1]*du_p[INDEX3(1,1,1,numEq,3)]+c23_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
-X_11_2 = -(c13_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c33_p[2]*du_p[INDEX3(1,1,2,numEq,3)]+c23_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
-X_11_3 = -(c13_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c33_p[3]*du_p[INDEX3(1,1,3,numEq,3)]+c23_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
-X_11_4 = -(c13_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c33_p[4]*du_p[INDEX3(1,1,4,numEq,3)]+c23_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
-X_11_5 = -(c13_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c33_p[5]*du_p[INDEX3(1,1,5,numEq,3)]+c23_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
-X_11_6 = -(c13_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c33_p[6]*du_p[INDEX3(1,1,6,numEq,3)]+c23_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
-X_11_7 = -(c13_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c33_p[7]*du_p[INDEX3(1,1,7,numEq,3)]+c23_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
+                                    X_11_0 = -(c13_p[0]*du_p[INDEX3(0,0,0,numEq,3)]+c33_p[0]*du_p[INDEX3(1,1,0,numEq,3)]+c23_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
+                                    X_11_1 = -(c13_p[1]*du_p[INDEX3(0,0,1,numEq,3)]+c33_p[1]*du_p[INDEX3(1,1,1,numEq,3)]+c23_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
+                                    X_11_2 = -(c13_p[2]*du_p[INDEX3(0,0,2,numEq,3)]+c33_p[2]*du_p[INDEX3(1,1,2,numEq,3)]+c23_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
+                                    X_11_3 = -(c13_p[3]*du_p[INDEX3(0,0,3,numEq,3)]+c33_p[3]*du_p[INDEX3(1,1,3,numEq,3)]+c23_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
+                                    X_11_4 = -(c13_p[4]*du_p[INDEX3(0,0,4,numEq,3)]+c33_p[4]*du_p[INDEX3(1,1,4,numEq,3)]+c23_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
+                                    X_11_5 = -(c13_p[5]*du_p[INDEX3(0,0,5,numEq,3)]+c33_p[5]*du_p[INDEX3(1,1,5,numEq,3)]+c23_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
+                                    X_11_6 = -(c13_p[6]*du_p[INDEX3(0,0,6,numEq,3)]+c33_p[6]*du_p[INDEX3(1,1,6,numEq,3)]+c23_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
+                                    X_11_7 = -(c13_p[7]*du_p[INDEX3(0,0,7,numEq,3)]+c33_p[7]*du_p[INDEX3(1,1,7,numEq,3)]+c23_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
 
-X_22_0 = -(c13_p[0]*du_p[INDEX3(0,0,0,numEq,3)] + c23_p[0]*du_p[INDEX3(1,1,0,numEq,3)] + c33_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
-X_22_1 = -(c13_p[1]*du_p[INDEX3(0,0,1,numEq,3)] + c23_p[1]*du_p[INDEX3(1,1,1,numEq,3)] + c33_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
-X_22_2 = -(c13_p[2]*du_p[INDEX3(0,0,2,numEq,3)] + c23_p[2]*du_p[INDEX3(1,1,2,numEq,3)] + c33_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
-X_22_3 = -(c13_p[3]*du_p[INDEX3(0,0,3,numEq,3)] + c23_p[3]*du_p[INDEX3(1,1,3,numEq,3)] + c33_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
-X_22_4 = -(c13_p[4]*du_p[INDEX3(0,0,4,numEq,3)] + c23_p[4]*du_p[INDEX3(1,1,4,numEq,3)] + c33_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
-X_22_5 = -(c13_p[5]*du_p[INDEX3(0,0,5,numEq,3)] + c23_p[5]*du_p[INDEX3(1,1,5,numEq,3)] + c33_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
-X_22_6 = -(c13_p[6]*du_p[INDEX3(0,0,6,numEq,3)] + c23_p[6]*du_p[INDEX3(1,1,6,numEq,3)] + c33_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
-X_22_7 = -(c13_p[7]*du_p[INDEX3(0,0,7,numEq,3)] + c23_p[7]*du_p[INDEX3(1,1,7,numEq,3)] + c33_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
+                                    X_22_0 = -(c13_p[0]*du_p[INDEX3(0,0,0,numEq,3)] + c23_p[0]*du_p[INDEX3(1,1,0,numEq,3)] + c33_p[0]*du_p[INDEX3(2,2,0,numEq,3)]);
+                                    X_22_1 = -(c13_p[1]*du_p[INDEX3(0,0,1,numEq,3)] + c23_p[1]*du_p[INDEX3(1,1,1,numEq,3)] + c33_p[1]*du_p[INDEX3(2,2,1,numEq,3)]);
+                                    X_22_2 = -(c13_p[2]*du_p[INDEX3(0,0,2,numEq,3)] + c23_p[2]*du_p[INDEX3(1,1,2,numEq,3)] + c33_p[2]*du_p[INDEX3(2,2,2,numEq,3)]);
+                                    X_22_3 = -(c13_p[3]*du_p[INDEX3(0,0,3,numEq,3)] + c23_p[3]*du_p[INDEX3(1,1,3,numEq,3)] + c33_p[3]*du_p[INDEX3(2,2,3,numEq,3)]);
+                                    X_22_4 = -(c13_p[4]*du_p[INDEX3(0,0,4,numEq,3)] + c23_p[4]*du_p[INDEX3(1,1,4,numEq,3)] + c33_p[4]*du_p[INDEX3(2,2,4,numEq,3)]);
+                                    X_22_5 = -(c13_p[5]*du_p[INDEX3(0,0,5,numEq,3)] + c23_p[5]*du_p[INDEX3(1,1,5,numEq,3)] + c33_p[5]*du_p[INDEX3(2,2,5,numEq,3)]);
+                                    X_22_6 = -(c13_p[6]*du_p[INDEX3(0,0,6,numEq,3)] + c23_p[6]*du_p[INDEX3(1,1,6,numEq,3)] + c33_p[6]*du_p[INDEX3(2,2,6,numEq,3)]);
+                                    X_22_7 = -(c13_p[7]*du_p[INDEX3(0,0,7,numEq,3)] + c23_p[7]*du_p[INDEX3(1,1,7,numEq,3)] + c33_p[7]*du_p[INDEX3(2,2,7,numEq,3)]);
                                 }
 
-const double Atmp0 = w72*(X_00_6 + X_00_7);
-const double Atmp1 = w66*(X_02_0 + X_02_4);
-const double Atmp2 = w64*(X_00_0 + X_00_1);
-const double Atmp3 = w68*(X_02_1 + X_02_2 + X_02_5 + X_02_6);
-const double Atmp4 = w65*(X_01_0 + X_01_2);
-const double Atmp5 = w70*(X_02_3 + X_02_7);
-const double Atmp6 = w67*(X_01_1 + X_01_3 + X_01_4 + X_01_6);
-const double Atmp7 = w71*(X_01_5 + X_01_7);
-const double Atmp8 = w69*(X_00_2 + X_00_3 + X_00_4 + X_00_5);
-const double Atmp9 = w72*(-X_00_6 - X_00_7);
-const double Atmp10 = w66*(X_02_1 + X_02_5);
-const double Atmp11 = w64*(-X_00_0 - X_00_1);
-const double Atmp12 = w68*(X_02_0 + X_02_3 + X_02_4 + X_02_7);
-const double Atmp13 = w65*(X_01_1 + X_01_3);
-const double Atmp14 = w70*(X_02_2 + X_02_6);
-const double Atmp15 = w67*(X_01_0 + X_01_2 + X_01_5 + X_01_7);
-const double Atmp16 = w71*(X_01_4 + X_01_6);
-const double Atmp17 = w69*(-X_00_2 - X_00_3 - X_00_4 - X_00_5);
-const double Atmp18 = w72*(X_00_4 + X_00_5);
-const double Atmp19 = w66*(X_02_2 + X_02_6);
-const double Atmp20 = w64*(X_00_2 + X_00_3);
-const double Atmp21 = w65*(-X_01_0 - X_01_2);
-const double Atmp22 = w70*(X_02_1 + X_02_5);
-const double Atmp23 = w67*(-X_01_1 - X_01_3 - X_01_4 - X_01_6);
-const double Atmp24 = w71*(-X_01_5 - X_01_7);
-const double Atmp25 = w69*(X_00_0 + X_00_1 + X_00_6 + X_00_7);
-const double Atmp26 = w72*(-X_00_4 - X_00_5);
-const double Atmp27 = w66*(X_02_3 + X_02_7);
-const double Atmp28 = w64*(-X_00_2 - X_00_3);
-const double Atmp29 = w65*(-X_01_1 - X_01_3);
-const double Atmp30 = w70*(X_02_0 + X_02_4);
-const double Atmp31 = w67*(-X_01_0 - X_01_2 - X_01_5 - X_01_7);
-const double Atmp32 = w71*(-X_01_4 - X_01_6);
-const double Atmp33 = w69*(-X_00_0 - X_00_1 - X_00_6 - X_00_7);
-const double Atmp34 = w72*(X_00_2 + X_00_3);
-const double Atmp35 = w66*(-X_02_0 - X_02_4);
-const double Atmp36 = w64*(X_00_4 + X_00_5);
-const double Atmp37 = w68*(-X_02_1 - X_02_2 - X_02_5 - X_02_6);
-const double Atmp38 = w65*(X_01_4 + X_01_6);
-const double Atmp39 = w70*(-X_02_3 - X_02_7);
-const double Atmp40 = w71*(X_01_1 + X_01_3);
-const double Atmp41 = w72*(-X_00_2 - X_00_3);
-const double Atmp42 = w66*(-X_02_1 - X_02_5);
-const double Atmp43 = w64*(-X_00_4 - X_00_5);
-const double Atmp44 = w68*(-X_02_0 - X_02_3 - X_02_4 - X_02_7);
-const double Atmp45 = w65*(X_01_5 + X_01_7);
-const double Atmp46 = w70*(-X_02_2 - X_02_6);
-const double Atmp47 = w71*(X_01_0 + X_01_2);
-const double Atmp48 = w72*(X_00_0 + X_00_1);
-const double Atmp49 = w66*(-X_02_2 - X_02_6);
-const double Atmp50 = w64*(X_00_6 + X_00_7);
-const double Atmp51 = w65*(-X_01_4 - X_01_6);
-const double Atmp52 = w70*(-X_02_1 - X_02_5);
-const double Atmp53 = w71*(-X_01_1 - X_01_3);
-const double Atmp54 = w72*(-X_00_0 - X_00_1);
-const double Atmp55 = w66*(-X_02_3 - X_02_7);
-const double Atmp56 = w64*(-X_00_6 - X_00_7);
-const double Atmp57 = w65*(-X_01_5 - X_01_7);
-const double Atmp58 = w70*(-X_02_0 - X_02_4);
-const double Atmp59 = w71*(-X_01_0 - X_01_2);
-EM_F[INDEX2(0,0,numEq)]+=Atmp0 + Atmp1 + Atmp2 + Atmp3 + Atmp4 + Atmp5 + Atmp6 + Atmp7 + Atmp8;
-EM_F[INDEX2(0,1,numEq)]+=Atmp10 + Atmp11 + Atmp12 + Atmp13 + Atmp14 + Atmp15 + Atmp16 + Atmp17 + Atmp9;
-EM_F[INDEX2(0,2,numEq)]+=Atmp12 + Atmp18 + Atmp19 + Atmp20 + Atmp21 + Atmp22 + Atmp23 + Atmp24 + Atmp25;
-EM_F[INDEX2(0,3,numEq)]+=Atmp26 + Atmp27 + Atmp28 + Atmp29 + Atmp3 + Atmp30 + Atmp31 + Atmp32 + Atmp33;
-EM_F[INDEX2(0,4,numEq)]+=Atmp15 + Atmp25 + Atmp34 + Atmp35 + Atmp36 + Atmp37 + Atmp38 + Atmp39 + Atmp40;
-EM_F[INDEX2(0,5,numEq)]+=Atmp33 + Atmp41 + Atmp42 + Atmp43 + Atmp44 + Atmp45 + Atmp46 + Atmp47 + Atmp6;
-EM_F[INDEX2(0,6,numEq)]+=Atmp31 + Atmp44 + Atmp48 + Atmp49 + Atmp50 + Atmp51 + Atmp52 + Atmp53 + Atmp8;
-EM_F[INDEX2(0,7,numEq)]+=Atmp17 + Atmp23 + Atmp37 + Atmp54 + Atmp55 + Atmp56 + Atmp57 + Atmp58 + Atmp59;
-const double Btmp0 = w72*(X_01_6 + X_01_7);
-const double Btmp1 = w66*(X_12_0 + X_12_4);
-const double Btmp2 = w64*(X_01_0 + X_01_1);
-const double Btmp3 = w68*(X_12_1 + X_12_2 + X_12_5 + X_12_6);
-const double Btmp4 = w65*(X_11_0 + X_11_2);
-const double Btmp5 = w70*(X_12_3 + X_12_7);
-const double Btmp6 = w67*(X_11_1 + X_11_3 + X_11_4 + X_11_6);
-const double Btmp7 = w71*(X_11_5 + X_11_7);
-const double Btmp8 = w69*(X_01_2 + X_01_3 + X_01_4 + X_01_5);
-const double Btmp9 = w72*(-X_01_6 - X_01_7);
-const double Btmp10 = w66*(X_12_1 + X_12_5);
-const double Btmp11 = w64*(-X_01_0 - X_01_1);
-const double Btmp12 = w68*(X_12_0 + X_12_3 + X_12_4 + X_12_7);
-const double Btmp13 = w65*(X_11_1 + X_11_3);
-const double Btmp14 = w70*(X_12_2 + X_12_6);
-const double Btmp15 = w67*(X_11_0 + X_11_2 + X_11_5 + X_11_7);
-const double Btmp16 = w71*(X_11_4 + X_11_6);
-const double Btmp17 = w69*(-X_01_2 - X_01_3 - X_01_4 - X_01_5);
-const double Btmp18 = w72*(X_01_4 + X_01_5);
-const double Btmp19 = w66*(X_12_2 + X_12_6);
-const double Btmp20 = w64*(X_01_2 + X_01_3);
-const double Btmp21 = w65*(-X_11_0 - X_11_2);
-const double Btmp22 = w70*(X_12_1 + X_12_5);
-const double Btmp23 = w67*(-X_11_1 - X_11_3 - X_11_4 - X_11_6);
-const double Btmp24 = w71*(-X_11_5 - X_11_7);
-const double Btmp25 = w69*(X_01_0 + X_01_1 + X_01_6 + X_01_7);
-const double Btmp26 = w72*(-X_01_4 - X_01_5);
-const double Btmp27 = w66*(X_12_3 + X_12_7);
-const double Btmp28 = w64*(-X_01_2 - X_01_3);
-const double Btmp29 = w65*(-X_11_1 - X_11_3);
-const double Btmp30 = w70*(X_12_0 + X_12_4);
-const double Btmp31 = w67*(-X_11_0 - X_11_2 - X_11_5 - X_11_7);
-const double Btmp32 = w71*(-X_11_4 - X_11_6);
-const double Btmp33 = w69*(-X_01_0 - X_01_1 - X_01_6 - X_01_7);
-const double Btmp34 = w72*(X_01_2 + X_01_3);
-const double Btmp35 = w66*(-X_12_0 - X_12_4);
-const double Btmp36 = w64*(X_01_4 + X_01_5);
-const double Btmp37 = w68*(-X_12_1 - X_12_2 - X_12_5 - X_12_6);
-const double Btmp38 = w65*(X_11_4 + X_11_6);
-const double Btmp39 = w70*(-X_12_3 - X_12_7);
-const double Btmp40 = w71*(X_11_1 + X_11_3);
-const double Btmp41 = w72*(-X_01_2 - X_01_3);
-const double Btmp42 = w66*(-X_12_1 - X_12_5);
-const double Btmp43 = w64*(-X_01_4 - X_01_5);
-const double Btmp44 = w68*(-X_12_0 - X_12_3 - X_12_4 - X_12_7);
-const double Btmp45 = w65*(X_11_5 + X_11_7);
-const double Btmp46 = w70*(-X_12_2 - X_12_6);
-const double Btmp47 = w71*(X_11_0 + X_11_2);
-const double Btmp48 = w72*(X_01_0 + X_01_1);
-const double Btmp49 = w66*(-X_12_2 - X_12_6);
-const double Btmp50 = w64*(X_01_6 + X_01_7);
-const double Btmp51 = w65*(-X_11_4 - X_11_6);
-const double Btmp52 = w70*(-X_12_1 - X_12_5);
-const double Btmp53 = w71*(-X_11_1 - X_11_3);
-const double Btmp54 = w72*(-X_01_0 - X_01_1);
-const double Btmp55 = w66*(-X_12_3 - X_12_7);
-const double Btmp56 = w64*(-X_01_6 - X_01_7);
-const double Btmp57 = w65*(-X_11_5 - X_11_7);
-const double Btmp58 = w70*(-X_12_0 - X_12_4);
-const double Btmp59 = w71*(-X_11_0 - X_11_2);
-EM_F[INDEX2(1,0,numEq)]+=Btmp0 + Btmp1 + Btmp2 + Btmp3 + Btmp4 + Btmp5 + Btmp6 + Btmp7 + Btmp8;
-EM_F[INDEX2(1,1,numEq)]+=Btmp10 + Btmp11 + Btmp12 + Btmp13 + Btmp14 + Btmp15 + Btmp16 + Btmp17 + Btmp9;
-EM_F[INDEX2(1,2,numEq)]+=Btmp12 + Btmp18 + Btmp19 + Btmp20 + Btmp21 + Btmp22 + Btmp23 + Btmp24 + Btmp25;
-EM_F[INDEX2(1,3,numEq)]+=Btmp26 + Btmp27 + Btmp28 + Btmp29 + Btmp3 + Btmp30 + Btmp31 + Btmp32 + Btmp33;
-EM_F[INDEX2(1,4,numEq)]+=Btmp15 + Btmp25 + Btmp34 + Btmp35 + Btmp36 + Btmp37 + Btmp38 + Btmp39 + Btmp40;
-EM_F[INDEX2(1,5,numEq)]+=Btmp33 + Btmp41 + Btmp42 + Btmp43 + Btmp44 + Btmp45 + Btmp46 + Btmp47 + Btmp6;
-EM_F[INDEX2(1,6,numEq)]+=Btmp31 + Btmp44 + Btmp48 + Btmp49 + Btmp50 + Btmp51 + Btmp52 + Btmp53 + Btmp8;
-EM_F[INDEX2(1,7,numEq)]+=Btmp17 + Btmp23 + Btmp37 + Btmp54 + Btmp55 + Btmp56 + Btmp57 + Btmp58 + Btmp59;
-const double Ctmp0 = w72*(X_02_6 + X_02_7);
-const double Ctmp1 = w66*(X_22_0 + X_22_4);
-const double Ctmp2 = w64*(X_02_0 + X_02_1);
-const double Ctmp3 = w68*(X_22_1 + X_22_2 + X_22_5 + X_22_6);
-const double Ctmp4 = w65*(X_12_0 + X_12_2);
-const double Ctmp5 = w70*(X_22_3 + X_22_7);
-const double Ctmp6 = w67*(X_12_1 + X_12_3 + X_12_4 + X_12_6);
-const double Ctmp7 = w71*(X_12_5 + X_12_7);
-const double Ctmp8 = w69*(X_02_2 + X_02_3 + X_02_4 + X_02_5);
-const double Ctmp9 = w72*(-X_02_6 - X_02_7);
-const double Ctmp10 = w66*(X_22_1 + X_22_5);
-const double Ctmp11 = w64*(-X_02_0 - X_02_1);
-const double Ctmp12 = w68*(X_22_0 + X_22_3 + X_22_4 + X_22_7);
-const double Ctmp13 = w65*(X_12_1 + X_12_3);
-const double Ctmp14 = w70*(X_22_2 + X_22_6);
-const double Ctmp15 = w67*(X_12_0 + X_12_2 + X_12_5 + X_12_7);
-const double Ctmp16 = w71*(X_12_4 + X_12_6);
-const double Ctmp17 = w69*(-X_02_2 - X_02_3 - X_02_4 - X_02_5);
-const double Ctmp18 = w72*(X_02_4 + X_02_5);
-const double Ctmp19 = w66*(X_22_2 + X_22_6);
-const double Ctmp20 = w64*(X_02_2 + X_02_3);
-const double Ctmp21 = w65*(-X_12_0 - X_12_2);
-const double Ctmp22 = w70*(X_22_1 + X_22_5);
-const double Ctmp23 = w67*(-X_12_1 - X_12_3 - X_12_4 - X_12_6);
-const double Ctmp24 = w71*(-X_12_5 - X_12_7);
-const double Ctmp25 = w69*(X_02_0 + X_02_1 + X_02_6 + X_02_7);
-const double Ctmp26 = w72*(-X_02_4 - X_02_5);
-const double Ctmp27 = w66*(X_22_3 + X_22_7);
-const double Ctmp28 = w64*(-X_02_2 - X_02_3);
-const double Ctmp29 = w65*(-X_12_1 - X_12_3);
-const double Ctmp30 = w70*(X_22_0 + X_22_4);
-const double Ctmp31 = w67*(-X_12_0 - X_12_2 - X_12_5 - X_12_7);
-const double Ctmp32 = w71*(-X_12_4 - X_12_6);
-const double Ctmp33 = w69*(-X_02_0 - X_02_1 - X_02_6 - X_02_7);
-const double Ctmp34 = w72*(X_02_2 + X_02_3);
-const double Ctmp35 = w66*(-X_22_0 - X_22_4);
-const double Ctmp36 = w64*(X_02_4 + X_02_5);
-const double Ctmp37 = w68*(-X_22_1 - X_22_2 - X_22_5 - X_22_6);
-const double Ctmp38 = w65*(X_12_4 + X_12_6);
-const double Ctmp39 = w70*(-X_22_3 - X_22_7);
-const double Ctmp40 = w71*(X_12_1 + X_12_3);
-const double Ctmp41 = w72*(-X_02_2 - X_02_3);
-const double Ctmp42 = w66*(-X_22_1 - X_22_5);
-const double Ctmp43 = w64*(-X_02_4 - X_02_5);
-const double Ctmp44 = w68*(-X_22_0 - X_22_3 - X_22_4 - X_22_7);
-const double Ctmp45 = w65*(X_12_5 + X_12_7);
-const double Ctmp46 = w70*(-X_22_2 - X_22_6);
-const double Ctmp47 = w71*(X_12_0 + X_12_2);
-const double Ctmp48 = w72*(X_02_0 + X_02_1);
-const double Ctmp49 = w66*(-X_22_2 - X_22_6);
-const double Ctmp50 = w64*(X_02_6 + X_02_7);
-const double Ctmp51 = w65*(-X_12_4 - X_12_6);
-const double Ctmp52 = w70*(-X_22_1 - X_22_5);
-const double Ctmp53 = w71*(-X_12_1 - X_12_3);
-const double Ctmp54 = w72*(-X_02_0 - X_02_1);
-const double Ctmp55 = w66*(-X_22_3 - X_22_7);
-const double Ctmp56 = w64*(-X_02_6 - X_02_7);
-const double Ctmp57 = w65*(-X_12_5 - X_12_7);
-const double Ctmp58 = w70*(-X_22_0 - X_22_4);
-const double Ctmp59 = w71*(-X_12_0 - X_12_2);
-EM_F[INDEX2(2,0,numEq)]+=Ctmp0 + Ctmp1 + Ctmp2 + Ctmp3 + Ctmp4 + Ctmp5 + Ctmp6 + Ctmp7 + Ctmp8;
-EM_F[INDEX2(2,1,numEq)]+=Ctmp10 + Ctmp11 + Ctmp12 + Ctmp13 + Ctmp14 + Ctmp15 + Ctmp16 + Ctmp17 + Ctmp9;
-EM_F[INDEX2(2,2,numEq)]+=Ctmp12 + Ctmp18 + Ctmp19 + Ctmp20 + Ctmp21 + Ctmp22 + Ctmp23 + Ctmp24 + Ctmp25;
-EM_F[INDEX2(2,3,numEq)]+=Ctmp26 + Ctmp27 + Ctmp28 + Ctmp29 + Ctmp3 + Ctmp30 + Ctmp31 + Ctmp32 + Ctmp33;
-EM_F[INDEX2(2,4,numEq)]+=Ctmp15 + Ctmp25 + Ctmp34 + Ctmp35 + Ctmp36 + Ctmp37 + Ctmp38 + Ctmp39 + Ctmp40;
-EM_F[INDEX2(2,5,numEq)]+=Ctmp33 + Ctmp41 + Ctmp42 + Ctmp43 + Ctmp44 + Ctmp45 + Ctmp46 + Ctmp47 + Ctmp6;
-EM_F[INDEX2(2,6,numEq)]+=Ctmp31 + Ctmp44 + Ctmp48 + Ctmp49 + Ctmp50 + Ctmp51 + Ctmp52 + Ctmp53 + Ctmp8;
-EM_F[INDEX2(2,7,numEq)]+=Ctmp17 + Ctmp23 + Ctmp37 + Ctmp54 + Ctmp55 + Ctmp56 + Ctmp57 + Ctmp58 + Ctmp59;
+                                const double Atmp0 = w72*(X_00_6 + X_00_7);
+                                const double Atmp1 = w66*(X_02_0 + X_02_4);
+                                const double Atmp2 = w64*(X_00_0 + X_00_1);
+                                const double Atmp3 = w68*(X_02_1 + X_02_2 + X_02_5 + X_02_6);
+                                const double Atmp4 = w65*(X_01_0 + X_01_2);
+                                const double Atmp5 = w70*(X_02_3 + X_02_7);
+                                const double Atmp6 = w67*(X_01_1 + X_01_3 + X_01_4 + X_01_6);
+                                const double Atmp7 = w71*(X_01_5 + X_01_7);
+                                const double Atmp8 = w69*(X_00_2 + X_00_3 + X_00_4 + X_00_5);
+                                const double Atmp9 = w72*(-X_00_6 - X_00_7);
+                                const double Atmp10 = w66*(X_02_1 + X_02_5);
+                                const double Atmp11 = w64*(-X_00_0 - X_00_1);
+                                const double Atmp12 = w68*(X_02_0 + X_02_3 + X_02_4 + X_02_7);
+                                const double Atmp13 = w65*(X_01_1 + X_01_3);
+                                const double Atmp14 = w70*(X_02_2 + X_02_6);
+                                const double Atmp15 = w67*(X_01_0 + X_01_2 + X_01_5 + X_01_7);
+                                const double Atmp16 = w71*(X_01_4 + X_01_6);
+                                const double Atmp17 = w69*(-X_00_2 - X_00_3 - X_00_4 - X_00_5);
+                                const double Atmp18 = w72*(X_00_4 + X_00_5);
+                                const double Atmp19 = w66*(X_02_2 + X_02_6);
+                                const double Atmp20 = w64*(X_00_2 + X_00_3);
+                                const double Atmp21 = w65*(-X_01_0 - X_01_2);
+                                const double Atmp22 = w70*(X_02_1 + X_02_5);
+                                const double Atmp23 = w67*(-X_01_1 - X_01_3 - X_01_4 - X_01_6);
+                                const double Atmp24 = w71*(-X_01_5 - X_01_7);
+                                const double Atmp25 = w69*(X_00_0 + X_00_1 + X_00_6 + X_00_7);
+                                const double Atmp26 = w72*(-X_00_4 - X_00_5);
+                                const double Atmp27 = w66*(X_02_3 + X_02_7);
+                                const double Atmp28 = w64*(-X_00_2 - X_00_3);
+                                const double Atmp29 = w65*(-X_01_1 - X_01_3);
+                                const double Atmp30 = w70*(X_02_0 + X_02_4);
+                                const double Atmp31 = w67*(-X_01_0 - X_01_2 - X_01_5 - X_01_7);
+                                const double Atmp32 = w71*(-X_01_4 - X_01_6);
+                                const double Atmp33 = w69*(-X_00_0 - X_00_1 - X_00_6 - X_00_7);
+                                const double Atmp34 = w72*(X_00_2 + X_00_3);
+                                const double Atmp35 = w66*(-X_02_0 - X_02_4);
+                                const double Atmp36 = w64*(X_00_4 + X_00_5);
+                                const double Atmp37 = w68*(-X_02_1 - X_02_2 - X_02_5 - X_02_6);
+                                const double Atmp38 = w65*(X_01_4 + X_01_6);
+                                const double Atmp39 = w70*(-X_02_3 - X_02_7);
+                                const double Atmp40 = w71*(X_01_1 + X_01_3);
+                                const double Atmp41 = w72*(-X_00_2 - X_00_3);
+                                const double Atmp42 = w66*(-X_02_1 - X_02_5);
+                                const double Atmp43 = w64*(-X_00_4 - X_00_5);
+                                const double Atmp44 = w68*(-X_02_0 - X_02_3 - X_02_4 - X_02_7);
+                                const double Atmp45 = w65*(X_01_5 + X_01_7);
+                                const double Atmp46 = w70*(-X_02_2 - X_02_6);
+                                const double Atmp47 = w71*(X_01_0 + X_01_2);
+                                const double Atmp48 = w72*(X_00_0 + X_00_1);
+                                const double Atmp49 = w66*(-X_02_2 - X_02_6);
+                                const double Atmp50 = w64*(X_00_6 + X_00_7);
+                                const double Atmp51 = w65*(-X_01_4 - X_01_6);
+                                const double Atmp52 = w70*(-X_02_1 - X_02_5);
+                                const double Atmp53 = w71*(-X_01_1 - X_01_3);
+                                const double Atmp54 = w72*(-X_00_0 - X_00_1);
+                                const double Atmp55 = w66*(-X_02_3 - X_02_7);
+                                const double Atmp56 = w64*(-X_00_6 - X_00_7);
+                                const double Atmp57 = w65*(-X_01_5 - X_01_7);
+                                const double Atmp58 = w70*(-X_02_0 - X_02_4);
+                                const double Atmp59 = w71*(-X_01_0 - X_01_2);
+                                const double Btmp0 = w72*(X_01_6 + X_01_7);
+                                const double Btmp1 = w66*(X_12_0 + X_12_4);
+                                const double Btmp2 = w64*(X_01_0 + X_01_1);
+                                const double Btmp3 = w68*(X_12_1 + X_12_2 + X_12_5 + X_12_6);
+                                const double Btmp4 = w65*(X_11_0 + X_11_2);
+                                const double Btmp5 = w70*(X_12_3 + X_12_7);
+                                const double Btmp6 = w67*(X_11_1 + X_11_3 + X_11_4 + X_11_6);
+                                const double Btmp7 = w71*(X_11_5 + X_11_7);
+                                const double Btmp8 = w69*(X_01_2 + X_01_3 + X_01_4 + X_01_5);
+                                const double Btmp9 = w72*(-X_01_6 - X_01_7);
+                                const double Btmp10 = w66*(X_12_1 + X_12_5);
+                                const double Btmp11 = w64*(-X_01_0 - X_01_1);
+                                const double Btmp12 = w68*(X_12_0 + X_12_3 + X_12_4 + X_12_7);
+                                const double Btmp13 = w65*(X_11_1 + X_11_3);
+                                const double Btmp14 = w70*(X_12_2 + X_12_6);
+                                const double Btmp15 = w67*(X_11_0 + X_11_2 + X_11_5 + X_11_7);
+                                const double Btmp16 = w71*(X_11_4 + X_11_6);
+                                const double Btmp17 = w69*(-X_01_2 - X_01_3 - X_01_4 - X_01_5);
+                                const double Btmp18 = w72*(X_01_4 + X_01_5);
+                                const double Btmp19 = w66*(X_12_2 + X_12_6);
+                                const double Btmp20 = w64*(X_01_2 + X_01_3);
+                                const double Btmp21 = w65*(-X_11_0 - X_11_2);
+                                const double Btmp22 = w70*(X_12_1 + X_12_5);
+                                const double Btmp23 = w67*(-X_11_1 - X_11_3 - X_11_4 - X_11_6);
+                                const double Btmp24 = w71*(-X_11_5 - X_11_7);
+                                const double Btmp25 = w69*(X_01_0 + X_01_1 + X_01_6 + X_01_7);
+                                const double Btmp26 = w72*(-X_01_4 - X_01_5);
+                                const double Btmp27 = w66*(X_12_3 + X_12_7);
+                                const double Btmp28 = w64*(-X_01_2 - X_01_3);
+                                const double Btmp29 = w65*(-X_11_1 - X_11_3);
+                                const double Btmp30 = w70*(X_12_0 + X_12_4);
+                                const double Btmp31 = w67*(-X_11_0 - X_11_2 - X_11_5 - X_11_7);
+                                const double Btmp32 = w71*(-X_11_4 - X_11_6);
+                                const double Btmp33 = w69*(-X_01_0 - X_01_1 - X_01_6 - X_01_7);
+                                const double Btmp34 = w72*(X_01_2 + X_01_3);
+                                const double Btmp35 = w66*(-X_12_0 - X_12_4);
+                                const double Btmp36 = w64*(X_01_4 + X_01_5);
+                                const double Btmp37 = w68*(-X_12_1 - X_12_2 - X_12_5 - X_12_6);
+                                const double Btmp38 = w65*(X_11_4 + X_11_6);
+                                const double Btmp39 = w70*(-X_12_3 - X_12_7);
+                                const double Btmp40 = w71*(X_11_1 + X_11_3);
+                                const double Btmp41 = w72*(-X_01_2 - X_01_3);
+                                const double Btmp42 = w66*(-X_12_1 - X_12_5);
+                                const double Btmp43 = w64*(-X_01_4 - X_01_5);
+                                const double Btmp44 = w68*(-X_12_0 - X_12_3 - X_12_4 - X_12_7);
+                                const double Btmp45 = w65*(X_11_5 + X_11_7);
+                                const double Btmp46 = w70*(-X_12_2 - X_12_6);
+                                const double Btmp47 = w71*(X_11_0 + X_11_2);
+                                const double Btmp48 = w72*(X_01_0 + X_01_1);
+                                const double Btmp49 = w66*(-X_12_2 - X_12_6);
+                                const double Btmp50 = w64*(X_01_6 + X_01_7);
+                                const double Btmp51 = w65*(-X_11_4 - X_11_6);
+                                const double Btmp52 = w70*(-X_12_1 - X_12_5);
+                                const double Btmp53 = w71*(-X_11_1 - X_11_3);
+                                const double Btmp54 = w72*(-X_01_0 - X_01_1);
+                                const double Btmp55 = w66*(-X_12_3 - X_12_7);
+                                const double Btmp56 = w64*(-X_01_6 - X_01_7);
+                                const double Btmp57 = w65*(-X_11_5 - X_11_7);
+                                const double Btmp58 = w70*(-X_12_0 - X_12_4);
+                                const double Btmp59 = w71*(-X_11_0 - X_11_2);
+                                const double Ctmp0 = w72*(X_02_6 + X_02_7);
+                                const double Ctmp1 = w66*(X_22_0 + X_22_4);
+                                const double Ctmp2 = w64*(X_02_0 + X_02_1);
+                                const double Ctmp3 = w68*(X_22_1 + X_22_2 + X_22_5 + X_22_6);
+                                const double Ctmp4 = w65*(X_12_0 + X_12_2);
+                                const double Ctmp5 = w70*(X_22_3 + X_22_7);
+                                const double Ctmp6 = w67*(X_12_1 + X_12_3 + X_12_4 + X_12_6);
+                                const double Ctmp7 = w71*(X_12_5 + X_12_7);
+                                const double Ctmp8 = w69*(X_02_2 + X_02_3 + X_02_4 + X_02_5);
+                                const double Ctmp9 = w72*(-X_02_6 - X_02_7);
+                                const double Ctmp10 = w66*(X_22_1 + X_22_5);
+                                const double Ctmp11 = w64*(-X_02_0 - X_02_1);
+                                const double Ctmp12 = w68*(X_22_0 + X_22_3 + X_22_4 + X_22_7);
+                                const double Ctmp13 = w65*(X_12_1 + X_12_3);
+                                const double Ctmp14 = w70*(X_22_2 + X_22_6);
+                                const double Ctmp15 = w67*(X_12_0 + X_12_2 + X_12_5 + X_12_7);
+                                const double Ctmp16 = w71*(X_12_4 + X_12_6);
+                                const double Ctmp17 = w69*(-X_02_2 - X_02_3 - X_02_4 - X_02_5);
+                                const double Ctmp18 = w72*(X_02_4 + X_02_5);
+                                const double Ctmp19 = w66*(X_22_2 + X_22_6);
+                                const double Ctmp20 = w64*(X_02_2 + X_02_3);
+                                const double Ctmp21 = w65*(-X_12_0 - X_12_2);
+                                const double Ctmp22 = w70*(X_22_1 + X_22_5);
+                                const double Ctmp23 = w67*(-X_12_1 - X_12_3 - X_12_4 - X_12_6);
+                                const double Ctmp24 = w71*(-X_12_5 - X_12_7);
+                                const double Ctmp25 = w69*(X_02_0 + X_02_1 + X_02_6 + X_02_7);
+                                const double Ctmp26 = w72*(-X_02_4 - X_02_5);
+                                const double Ctmp27 = w66*(X_22_3 + X_22_7);
+                                const double Ctmp28 = w64*(-X_02_2 - X_02_3);
+                                const double Ctmp29 = w65*(-X_12_1 - X_12_3);
+                                const double Ctmp30 = w70*(X_22_0 + X_22_4);
+                                const double Ctmp31 = w67*(-X_12_0 - X_12_2 - X_12_5 - X_12_7);
+                                const double Ctmp32 = w71*(-X_12_4 - X_12_6);
+                                const double Ctmp33 = w69*(-X_02_0 - X_02_1 - X_02_6 - X_02_7);
+                                const double Ctmp34 = w72*(X_02_2 + X_02_3);
+                                const double Ctmp35 = w66*(-X_22_0 - X_22_4);
+                                const double Ctmp36 = w64*(X_02_4 + X_02_5);
+                                const double Ctmp37 = w68*(-X_22_1 - X_22_2 - X_22_5 - X_22_6);
+                                const double Ctmp38 = w65*(X_12_4 + X_12_6);
+                                const double Ctmp39 = w70*(-X_22_3 - X_22_7);
+                                const double Ctmp40 = w71*(X_12_1 + X_12_3);
+                                const double Ctmp41 = w72*(-X_02_2 - X_02_3);
+                                const double Ctmp42 = w66*(-X_22_1 - X_22_5);
+                                const double Ctmp43 = w64*(-X_02_4 - X_02_5);
+                                const double Ctmp44 = w68*(-X_22_0 - X_22_3 - X_22_4 - X_22_7);
+                                const double Ctmp45 = w65*(X_12_5 + X_12_7);
+                                const double Ctmp46 = w70*(-X_22_2 - X_22_6);
+                                const double Ctmp47 = w71*(X_12_0 + X_12_2);
+                                const double Ctmp48 = w72*(X_02_0 + X_02_1);
+                                const double Ctmp49 = w66*(-X_22_2 - X_22_6);
+                                const double Ctmp50 = w64*(X_02_6 + X_02_7);
+                                const double Ctmp51 = w65*(-X_12_4 - X_12_6);
+                                const double Ctmp52 = w70*(-X_22_1 - X_22_5);
+                                const double Ctmp53 = w71*(-X_12_1 - X_12_3);
+                                const double Ctmp54 = w72*(-X_02_0 - X_02_1);
+                                const double Ctmp55 = w66*(-X_22_3 - X_22_7);
+                                const double Ctmp56 = w64*(-X_02_6 - X_02_7);
+                                const double Ctmp57 = w65*(-X_12_5 - X_12_7);
+                                const double Ctmp58 = w70*(-X_22_0 - X_22_4);
+                                const double Ctmp59 = w71*(-X_12_0 - X_12_2);
+                                EM_F[INDEX2(0,0,numEq)]+=Atmp0 + Atmp1 + Atmp2 + Atmp3 + Atmp4 + Atmp5 + Atmp6 + Atmp7 + Atmp8;
+                                EM_F[INDEX2(1,0,numEq)]+=Btmp0 + Btmp1 + Btmp2 + Btmp3 + Btmp4 + Btmp5 + Btmp6 + Btmp7 + Btmp8;
+                                EM_F[INDEX2(2,0,numEq)]+=Ctmp0 + Ctmp1 + Ctmp2 + Ctmp3 + Ctmp4 + Ctmp5 + Ctmp6 + Ctmp7 + Ctmp8;
+                                EM_F[INDEX2(0,1,numEq)]+=Atmp10 + Atmp11 + Atmp12 + Atmp13 + Atmp14 + Atmp15 + Atmp16 + Atmp17 + Atmp9;
+                                EM_F[INDEX2(1,1,numEq)]+=Btmp10 + Btmp11 + Btmp12 + Btmp13 + Btmp14 + Btmp15 + Btmp16 + Btmp17 + Btmp9;
+                                EM_F[INDEX2(2,1,numEq)]+=Ctmp10 + Ctmp11 + Ctmp12 + Ctmp13 + Ctmp14 + Ctmp15 + Ctmp16 + Ctmp17 + Ctmp9;
+                                EM_F[INDEX2(0,2,numEq)]+=Atmp12 + Atmp18 + Atmp19 + Atmp20 + Atmp21 + Atmp22 + Atmp23 + Atmp24 + Atmp25;
+                                EM_F[INDEX2(1,2,numEq)]+=Btmp12 + Btmp18 + Btmp19 + Btmp20 + Btmp21 + Btmp22 + Btmp23 + Btmp24 + Btmp25;
+                                EM_F[INDEX2(2,2,numEq)]+=Ctmp12 + Ctmp18 + Ctmp19 + Ctmp20 + Ctmp21 + Ctmp22 + Ctmp23 + Ctmp24 + Ctmp25;
+                                EM_F[INDEX2(0,3,numEq)]+=Atmp26 + Atmp27 + Atmp28 + Atmp29 + Atmp3 + Atmp30 + Atmp31 + Atmp32 + Atmp33;
+                                EM_F[INDEX2(1,3,numEq)]+=Btmp26 + Btmp27 + Btmp28 + Btmp29 + Btmp3 + Btmp30 + Btmp31 + Btmp32 + Btmp33;
+                                EM_F[INDEX2(2,3,numEq)]+=Ctmp26 + Ctmp27 + Ctmp28 + Ctmp29 + Ctmp3 + Ctmp30 + Ctmp31 + Ctmp32 + Ctmp33;
+                                EM_F[INDEX2(0,4,numEq)]+=Atmp15 + Atmp25 + Atmp34 + Atmp35 + Atmp36 + Atmp37 + Atmp38 + Atmp39 + Atmp40;
+                                EM_F[INDEX2(1,4,numEq)]+=Btmp15 + Btmp25 + Btmp34 + Btmp35 + Btmp36 + Btmp37 + Btmp38 + Btmp39 + Btmp40;
+                                EM_F[INDEX2(2,4,numEq)]+=Ctmp15 + Ctmp25 + Ctmp34 + Ctmp35 + Ctmp36 + Ctmp37 + Ctmp38 + Ctmp39 + Ctmp40;
+                                EM_F[INDEX2(0,5,numEq)]+=Atmp33 + Atmp41 + Atmp42 + Atmp43 + Atmp44 + Atmp45 + Atmp46 + Atmp47 + Atmp6;
+                                EM_F[INDEX2(1,5,numEq)]+=Btmp33 + Btmp41 + Btmp42 + Btmp43 + Btmp44 + Btmp45 + Btmp46 + Btmp47 + Btmp6;
+                                EM_F[INDEX2(2,5,numEq)]+=Ctmp33 + Ctmp41 + Ctmp42 + Ctmp43 + Ctmp44 + Ctmp45 + Ctmp46 + Ctmp47 + Ctmp6;
+                                EM_F[INDEX2(0,6,numEq)]+=Atmp31 + Atmp44 + Atmp48 + Atmp49 + Atmp50 + Atmp51 + Atmp52 + Atmp53 + Atmp8;
+                                EM_F[INDEX2(1,6,numEq)]+=Btmp31 + Btmp44 + Btmp48 + Btmp49 + Btmp50 + Btmp51 + Btmp52 + Btmp53 + Btmp8;
+                                EM_F[INDEX2(2,6,numEq)]+=Ctmp31 + Ctmp44 + Ctmp48 + Ctmp49 + Ctmp50 + Ctmp51 + Ctmp52 + Ctmp53 + Ctmp8;
+                                EM_F[INDEX2(0,7,numEq)]+=Atmp17 + Atmp23 + Atmp37 + Atmp54 + Atmp55 + Atmp56 + Atmp57 + Atmp58 + Atmp59;
+                                EM_F[INDEX2(1,7,numEq)]+=Btmp17 + Btmp23 + Btmp37 + Btmp54 + Btmp55 + Btmp56 + Btmp57 + Btmp58 + Btmp59;
+                                EM_F[INDEX2(2,7,numEq)]+=Ctmp17 + Ctmp23 + Ctmp37 + Ctmp54 + Ctmp55 + Ctmp56 + Ctmp57 + Ctmp58 + Ctmp59;
                             } else { // constant data
                                 const double wX01 = 18*w56*-(c66_p[0]*(du_p[INDEX2(0,1,numEq)] + du_p[INDEX2(1,0,numEq)]));
                                 const double wX10 = 18*w55*-(c66_p[0]*(du_p[INDEX2(0,1,numEq)] + du_p[INDEX2(1,0,numEq)]));
@@ -2341,7 +2361,7 @@ EM_F[INDEX2(2,7,numEq)]+=Ctmp17 + Ctmp23 + Ctmp37 + Ctmp54 + Ctmp55 + Ctmp56 + C
                                     wX11 = 18*w56*-(c12_p[0]* du_p[INDEX2(0,0,numEq)] + c11_p[0] * du_p[INDEX2(1,1,numEq)] + c13_p[0]*du_p[INDEX2(2,2,numEq)]);
                                     wX22 = 18*w54*-(c13_p[0]*(du_p[INDEX2(0,0,numEq)] + du_p[INDEX2(1,1,numEq)]) + c33_p[0]* du_p[INDEX2(2,2,numEq)]);
                                     wX02 = 18*w54*-(c44_p[0]*(du_p[INDEX2(2,0,numEq)] + du_p[INDEX2(0,2,numEq)]));
-                                    wX20 = 18*w55*-(c44_p[0]*(du_p[INDEX2(2,0,numEq)] + du_p[INDEX2(0,2,numEq)]));                                
+                                    wX20 = 18*w55*-(c44_p[0]*(du_p[INDEX2(2,0,numEq)] + du_p[INDEX2(0,2,numEq)]));                    
                                 } else { // isHTI
                                     const double *c23_p = c23.getSampleDataRO(e);
                                     wX00 = 18*w55*-(c11_p[0]* du_p[INDEX2(0,0,numEq)] + c13_p[0] * (du_p[INDEX2(1,1,numEq)] + du_p[INDEX2(2,2,numEq)]));
@@ -2359,7 +2379,7 @@ EM_F[INDEX2(2,7,numEq)]+=Ctmp17 + Ctmp23 + Ctmp37 + Ctmp54 + Ctmp55 + Ctmp56 + C
                                 EM_F[INDEX2(0,5,numEq)]+=-wX00 + wX01 - wX02;
                                 EM_F[INDEX2(0,6,numEq)]+= wX00 - wX01 - wX02;
                                 EM_F[INDEX2(0,7,numEq)]+=-wX00 - wX01 - wX02;
-                                
+                    
                                 EM_F[INDEX2(1,0,numEq)]+= wX10 + wX11 + wX12;
                                 EM_F[INDEX2(1,1,numEq)]+=-wX10 + wX11 + wX12;
                                 EM_F[INDEX2(1,2,numEq)]+= wX10 - wX11 + wX12;
@@ -2368,7 +2388,7 @@ EM_F[INDEX2(2,7,numEq)]+=Ctmp17 + Ctmp23 + Ctmp37 + Ctmp54 + Ctmp55 + Ctmp56 + C
                                 EM_F[INDEX2(1,5,numEq)]+=-wX10 + wX11 - wX12;
                                 EM_F[INDEX2(1,6,numEq)]+= wX10 - wX11 - wX12;
                                 EM_F[INDEX2(1,7,numEq)]+=-wX10 - wX11 - wX12;
-                                
+                    
                                 EM_F[INDEX2(2,0,numEq)]+= wX20 + wX21 + wX22;
                                 EM_F[INDEX2(2,1,numEq)]+=-wX20 + wX21 + wX22;
                                 EM_F[INDEX2(2,2,numEq)]+= wX20 - wX21 + wX22;
@@ -2383,7 +2403,6 @@ EM_F[INDEX2(2,7,numEq)]+=Ctmp17 + Ctmp23 + Ctmp37 + Ctmp54 + Ctmp55 + Ctmp56 + C
                         // process Y //
                         ///////////////
                         if (!Y.isEmpty()) {
-                            add_EM_F=true;
                             const double* Y_p=Y.getSampleDataRO(e);
                             if (Y.actsExpanded()) {
                                 for (index_t k=0; k<numEq; k++) {
diff --git a/ripley/src/WaveAssembler3D.h b/ripley/src/WaveAssembler3D.h
index 03e1494..66fb50b 100644
--- a/ripley/src/WaveAssembler3D.h
+++ b/ripley/src/WaveAssembler3D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -37,31 +37,31 @@ public:
 
     void assemblePDESingle(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDESingle() not supported by this assembler");
     }
     void assemblePDEBoundarySingle(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySingle() not supported by this assembler");
     }
     void assemblePDESingleReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDESingleReduced() not supported by this assembler");
     }
     void assemblePDEBoundarySingleReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySingleReduced() not supported by this assembler");
     }
     void assemblePDEBoundarySystem(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySystem() not supported by this assembler");
     }
     void assemblePDESystemReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDESystemReduced() not supported by this assembler");
     }
     void assemblePDEBoundarySystemReduced(escript::AbstractSystemMatrix* mat,
                            escript::Data& rhs, const DataMap& coefs) const {
-        throw RipleyException("This assembly not supported by this assembler");
+        throw RipleyException("assemblePDEBoundarySystemReduced() not supported by this assembler");
     }
 
     void collateFunctionSpaceTypes(std::vector<int>& fsTypes,
diff --git a/ripley/src/blocktools.cpp b/ripley/src/blocktools.cpp
index 205a268..7d4c684 100644
--- a/ripley/src/blocktools.cpp
+++ b/ripley/src/blocktools.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/blocktools.h b/ripley/src/blocktools.h
index 301caae..56a7b80 100644
--- a/ripley/src/blocktools.h
+++ b/ripley/src/blocktools.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/blocktools2.cpp b/ripley/src/blocktools2.cpp
index e7459e9..8cb1369 100644
--- a/ripley/src/blocktools2.cpp
+++ b/ripley/src/blocktools2.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/domainhelpers.cpp b/ripley/src/domainhelpers.cpp
index daa5af3..7accdcd 100644
--- a/ripley/src/domainhelpers.cpp
+++ b/ripley/src/domainhelpers.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <ripley/domainhelpers.h>
 #include <ripley/RipleyException.h>
 #include <cmath>
diff --git a/ripley/src/domainhelpers.h b/ripley/src/domainhelpers.h
index 81e2272..3ebbe6e 100644
--- a/ripley/src/domainhelpers.h
+++ b/ripley/src/domainhelpers.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/src/generate_assemblage_cpp.py b/ripley/src/generate_assemblage_cpp.py
index e5ded83..e27a9e1 100644
--- a/ripley/src/generate_assemblage_cpp.py
+++ b/ripley/src/generate_assemblage_cpp.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/ripley/src/ripleycpp.cpp b/ripley/src/ripleycpp.cpp
index 97f3781..f937f38 100644
--- a/ripley/src/ripleycpp.cpp
+++ b/ripley/src/ripleycpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,9 +14,14 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <ripley/AbstractAssembler.h>
 #include <ripley/Brick.h>
+#include <ripley/MultiBrick.h>
 #include <ripley/Rectangle.h>
+#include <ripley/MultiRectangle.h>
 #include <esysUtils/esysExceptionTranslator.h>
 
 #include <boost/python.hpp> 
@@ -226,8 +231,176 @@ escript::Domain_ptr _brick(double _n0, double _n1, double _n2, const object& l0,
                                             points, tags, tagstonames, world));
 }
 
-//const int _q[]={0x61686969,0x746c4144,0x79616e43};
-const int _q[]={0x62207363, 0x6574735F, 0x2020214e};
+escript::Domain_ptr _multibrick(double _n0, double _n1, double _n2, const object& l0,
+                 const object& l1, const object& l2, int d0, int d1, int d2,
+                 const object& objpoints, const object& objtags, escript::SubWorld_ptr world,
+                 unsigned int multiplier)
+{
+    dim_t n0=static_cast<dim_t>(_n0), n1=static_cast<dim_t>(_n1), n2=static_cast<dim_t>(_n2);
+    double x0=0., x1=1., y0=0., y1=1., z0=0., z1=1.;
+    if (extract<tuple>(l0).check()) {
+        tuple x=extract<tuple>(l0);
+        if (len(x)==2) {
+            x0=extract<double>(x[0]);
+            x1=extract<double>(x[1]);
+        } else
+            throw RipleyException("Argument l0 must be a float or 2-tuple");
+    } else if (extract<double>(l0).check()) {
+        x1=extract<double>(l0);
+    } else
+        throw RipleyException("Argument l0 must be a float or 2-tuple");
+
+    if (extract<tuple>(l1).check()) {
+        tuple y=extract<tuple>(l1);
+        if (len(y)==2) {
+            y0=extract<double>(y[0]);
+            y1=extract<double>(y[1]);
+        } else
+            throw RipleyException("Argument l1 must be a float or 2-tuple");
+    } else if (extract<double>(l1).check()) {
+        y1=extract<double>(l1);
+    } else
+        throw RipleyException("Argument l1 must be a float or 2-tuple");
+
+    if (extract<tuple>(l2).check()) {
+        tuple z=extract<tuple>(l2);
+        if (len(z)==2) {
+            z0=extract<double>(z[0]);
+            z1=extract<double>(z[1]);
+        } else
+            throw RipleyException("Argument l2 must be a float or 2-tuple");
+    } else if (extract<double>(l2).check()) {
+        z1=extract<double>(l2);
+    } else
+        throw RipleyException("Argument l2 must be a float or 2-tuple");
+    boost::python::list pypoints=extract<boost::python::list>(objpoints);
+    boost::python::list pytags=extract<boost::python::list>(objtags);
+    int numpts=extract<int>(pypoints.attr("__len__")());
+    int numtags=extract<int>(pytags.attr("__len__")());
+    std::vector<double> points;
+    std::vector<int> tags;
+    tags.resize(numtags, -1);
+    for (int i=0;i<numpts;++i) {
+        tuple temp = extract<tuple>(pypoints[i]);
+        int l=extract<int>(temp.attr("__len__")());
+        if (l != 3)
+            throw RipleyException("Number of coordinates for each dirac point must match dimensions.");
+        for (int k=0;k<l;++k) {
+            points.push_back(extract<double>(temp[k]));
+        }
+    }
+    std::map<std::string, int> tagstonames;
+    int curmax=40;
+    // but which order to assign tags to names?????
+    for (int i=0;i<numtags;++i) {
+        extract<int> ex_int(pytags[i]);
+        extract<std::string> ex_str(pytags[i]);
+        if (ex_int.check()) {
+            tags[i]=ex_int();
+            if (tags[i]>= curmax) {
+                curmax=tags[i]+1;
+            }
+        } else if (ex_str.check()) {
+            std::string s=ex_str();
+            std::map<std::string, int>::iterator it=tagstonames.find(s);
+            if (it!=tagstonames.end()) {
+                // we have the tag already so look it up
+                tags[i]=it->second;
+            } else {
+                tagstonames[s]=curmax;
+                tags[i]=curmax;
+                curmax++;
+            }
+        } else {
+            throw RipleyException("Error - Unable to extract tag value.");
+        }
+    }
+    if (numtags != numpts)
+        throw RipleyException("Number of tags does not match number of points.");
+    return escript::Domain_ptr(new MultiBrick(n0,n1,n2, x0,y0,z0, x1,y1,z1, d0,d1,d2,
+                                            points, tags, tagstonames, world,
+                                            multiplier));
+}
+
+escript::Domain_ptr _multirectangle(double _n0, double _n1, const object& l0,
+                               const object& l1, int d0, int d1, 
+                               const object& objpoints, const object& objtags,
+                               escript::SubWorld_ptr world,
+                               unsigned int multiplier)
+{
+    dim_t n0=static_cast<dim_t>(_n0), n1=static_cast<dim_t>(_n1);
+    double x0=0., x1=1., y0=0., y1=1.;
+    if (extract<tuple>(l0).check()) {
+        tuple x=extract<tuple>(l0);
+        if (len(x)==2) {
+            x0=extract<double>(x[0]);
+            x1=extract<double>(x[1]);
+        } else
+            throw RipleyException("Argument l0 must be a float or 2-tuple");
+    } else if (extract<double>(l0).check()) {
+        x1=extract<double>(l0);
+    } else
+        throw RipleyException("Argument l0 must be a float or 2-tuple");
+
+    if (extract<tuple>(l1).check()) {
+        tuple y=extract<tuple>(l1);
+        if (len(y)==2) {
+            y0=extract<double>(y[0]);
+            y1=extract<double>(y[1]);
+        } else
+            throw RipleyException("Argument l1 must be a float or 2-tuple");
+    } else if (extract<double>(l1).check()) {
+        y1=extract<double>(l1);
+    } else
+        throw RipleyException("Argument l1 must be a float or 2-tuple");
+    boost::python::list pypoints=extract<boost::python::list>(objpoints);
+    boost::python::list pytags=extract<boost::python::list>(objtags);
+    int numpts=extract<int>(pypoints.attr("__len__")());
+    int numtags=extract<int>(pytags.attr("__len__")());
+    std::vector<double> points;
+    std::vector<int> tags;
+    tags.resize(numtags, -1);
+    for (int i=0;i<numpts;++i) {
+        tuple temp = extract<tuple>(pypoints[i]);
+        int l=extract<int>(temp.attr("__len__")());
+        if (l != 2)
+            throw RipleyException("Number of coordinates for each dirac point must match dimensions.");
+        for (int k=0;k<l;++k) {
+            points.push_back(extract<double>(temp[k]));
+        }
+    }
+    std::map<std::string, int> tagstonames;
+    int curmax=40;
+    // but which order to assign tags to names?????
+    for (int i=0;i<numtags;++i) {
+        extract<int> ex_int(pytags[i]);
+        extract<std::string> ex_str(pytags[i]);
+        if (ex_int.check()) {
+            tags[i]=ex_int();
+            if (tags[i] >= curmax) {
+                curmax=tags[i]+1;
+            }
+        } else if (ex_str.check()) {
+            std::string s=ex_str();
+            std::map<std::string, int>::iterator it=tagstonames.find(s);
+            if (it!=tagstonames.end()) {
+                // we have the tag already so look it up
+                tags[i]=it->second;
+            } else {
+                tagstonames[s]=curmax;
+                tags[i]=curmax;
+                curmax++;
+            }
+        } else {
+            throw RipleyException("Error - Unable to extract tag value.");
+        }
+    }
+    if (numtags != numpts)
+        throw RipleyException("Number of tags does not match number of points.");
+    return escript::Domain_ptr(new MultiRectangle(n0,n1, x0,y0, x1,y1, d0,d1,
+                                 points, tags, tagstonames, world, multiplier));
+}
+
 escript::Domain_ptr _rectangle(double _n0, double _n1, const object& l0,
                                const object& l1, int d0, int d1, 
                                const object& objpoints, const object& objtags,
@@ -306,7 +479,6 @@ escript::Domain_ptr _rectangle(double _n0, double _n1, const object& l0,
     return escript::Domain_ptr(new Rectangle(n0,n1, x0,y0, x1,y1, d0,d1,
                                              points, tags, tagstonames, world));
 }
-std::string _who(){int a[]={_q[0]^42,_q[1]^42,_q[2]^42,0};return (char*)&a[0];}
 
 } // end of namespace ripley
 
@@ -329,45 +501,79 @@ BOOST_PYTHON_MODULE(ripleycpp)
     scope().attr("DATATYPE_FLOAT32") = (int)ripley::DATATYPE_FLOAT32;
     scope().attr("DATATYPE_FLOAT64") = (int)ripley::DATATYPE_FLOAT64;
 
-    def("Brick", ripley::_brick, (arg("n0"),arg("n1"),arg("n2"),arg("l0")=1.0,arg("l1")=1.0,arg("l2")=1.0,
-        arg("d0")=-1,arg("d1")=-1,arg("d2")=-1,arg("diracPoints")=list(),arg("diracTags")=list(), arg("escriptworld")=escript::SubWorld_ptr()),
-"Creates a hexagonal mesh with n0 x n1 x n2 elements over the brick [0,l0] x [0,l1] x [0,l2].\n\n"
-":param n0: number of elements in direction 0\n:type n0: ``int``\n"
-":param n1: number of elements in direction 1\n:type n1: ``int``\n"
-":param n2: number of elements in direction 2\n:type n2: ``int``\n"
-":param l0: length of side 0 or coordinate range of side 0\n:type l0: ``float`` or ``tuple``\n"
-":param l1: length of side 1 or coordinate range of side 1\n:type l1: ``float`` or ``tuple``\n"
-":param l2: length of side 2 or coordinate range of side 2\n:type l2: ``float`` or ``tuple``\n"
-":param d0: number of subdivisions in direction 0\n:type d0: ``int``\n"
-":param d1: number of subdivisions in direction 1\n:type d1: ``int``\n"
-":param d2: number of subdivisions in direction 2\n:type d2: ``int``");
-
-    def("Rectangle", ripley::_rectangle, (arg("n0"),arg("n1"),arg("l0")=1.0,arg("l1")=1.0,arg("d0")=-1,arg("d1")=-1,arg("diracPoints")=list(),arg("diracTags")=list(), arg("escriptworld")=escript::SubWorld_ptr()),
-"Creates a rectangular mesh with n0 x n1 elements over the rectangle [0,l0] x [0,l1].\n\n"
-":param n0: number of elements in direction 0\n:type n0: ``int``\n"
-":param n1: number of elements in direction 1\n:type n1: ``int``\n"
-":param l0: length of side 0 or coordinate range of side 0\n:type l0: ``float`` or ``tuple``\n"
-":param l1: length of side 1 or coordinate range of side 1\n:type l1: ``float`` or ``tuple``\n"
-":param d0: number of subdivisions in direction 0\n:type d0: ``int``\n"
-":param d1: number of subdivisions in direction 1\n:type d1: ``int``");
-    def("_theculprit_", ripley::_who);
+    def("Brick", ripley::_brick, (arg("n0"),arg("n1"),arg("n2"),arg("l0")=1.0,
+        arg("l1")=1.0,arg("l2")=1.0,arg("d0")=-1,arg("d1")=-1,arg("d2")=-1,
+        arg("diracPoints")=list(),arg("diracTags")=list(),
+        arg("escriptworld")=escript::SubWorld_ptr()),
+        "Creates a hexagonal mesh with n0 x n1 x n2 elements over the brick [0,l0] x [0,l1] x [0,l2].\n\n"
+        ":param n0: number of elements in direction 0\n:type n0: ``int``\n"
+        ":param n1: number of elements in direction 1\n:type n1: ``int``\n"
+        ":param n2: number of elements in direction 2\n:type n2: ``int``\n"
+        ":param l0: length of side 0 or coordinate range of side 0\n:type l0: ``float`` or ``tuple``\n"
+        ":param l1: length of side 1 or coordinate range of side 1\n:type l1: ``float`` or ``tuple``\n"
+        ":param l2: length of side 2 or coordinate range of side 2\n:type l2: ``float`` or ``tuple``\n"
+        ":param d0: number of subdivisions in direction 0\n:type d0: ``int``\n"
+        ":param d1: number of subdivisions in direction 1\n:type d1: ``int``\n"
+        ":param d2: number of subdivisions in direction 2\n:type d2: ``int``");
+
+    def("Rectangle", ripley::_rectangle, (arg("n0"),arg("n1"),arg("l0")=1.0,
+        arg("l1")=1.0,arg("d0")=-1,arg("d1")=-1,arg("diracPoints")=list(),
+        arg("diracTags")=list(), arg("escriptworld")=escript::SubWorld_ptr()),
+        "Creates a rectangular mesh with n0 x n1 elements over the rectangle [0,l0] x [0,l1].\n\n"
+        ":param n0: number of elements in direction 0\n:type n0: ``int``\n"
+        ":param n1: number of elements in direction 1\n:type n1: ``int``\n"
+        ":param l0: length of side 0 or coordinate range of side 0\n:type l0: ``float`` or ``tuple``\n"
+        ":param l1: length of side 1 or coordinate range of side 1\n:type l1: ``float`` or ``tuple``\n"
+        ":param d0: number of subdivisions in direction 0\n:type d0: ``int``\n"
+        ":param d1: number of subdivisions in direction 1\n:type d1: ``int``");
+
+    def("MultiRectangle", ripley::_multirectangle, (arg("n0"),arg("n1"),
+        arg("l0")=1.0,arg("l1")=1.0,arg("d0")=-1,arg("d1")=-1,
+        arg("diracPoints")=list(),arg("diracTags")=list(),
+        arg("escriptworld")=escript::SubWorld_ptr(), arg("multiplier")=1),
+        "Creates a rectangular mesh with n0 x n1 parent elements over the "
+        "rectangle [0,l0] x [0,l1], each parent element is divided ``multiplier`` times.\n\n"
+        ":param n0: number of elements in direction 0\n:type n0: ``int``\n"
+        ":param n1: number of elements in direction 1\n:type n1: ``int``\n"
+        ":param l0: length of side 0 or coordinate range of side 0\n:type l0: ``float`` or ``tuple``\n"
+        ":param l1: length of side 1 or coordinate range of side 1\n:type l1: ``float`` or ``tuple``\n"
+        ":param d0: number of subdivisions in direction 0\n:type d0: ``int``\n"
+        ":param d1: number of subdivisions in direction 1\n:type d1: ``int``\n"
+        ":param multiplier: size of overlap\n:type multiplier: ``unsigned int``");
+
+    def("MultiBrick", ripley::_multibrick, (arg("n0"),arg("n1"),arg("n2"),
+        arg("l0")=1.0,arg("l1")=1.0,arg("l2")=1.0,arg("d0")=-1,arg("d1")=-1,
+        arg("d2")=-1,arg("diracPoints")=list(),arg("diracTags")=list(),
+        arg("escriptworld")=escript::SubWorld_ptr(), arg("multiplier")=1),
+        "Creates a hexagonal mesh with n0 x n1 x n2 parent elements over the "
+        "brick [0,l0] x [0,l1] x [0,l2], each parent element is divided ``multiplier`` times.\n\n"
+        ":param n0: number of elements in direction 0\n:type n0: ``int``\n"
+        ":param n1: number of elements in direction 1\n:type n1: ``int``\n"
+        ":param n2: number of elements in direction 2\n:type n2: ``int``\n"
+        ":param l0: length of side 0 or coordinate range of side 0\n:type l0: ``float`` or ``tuple``\n"
+        ":param l1: length of side 1 or coordinate range of side 1\n:type l1: ``float`` or ``tuple``\n"
+        ":param l2: length of side 2 or coordinate range of side 2\n:type l2: ``float`` or ``tuple``\n"
+        ":param d0: number of subdivisions in direction 0\n:type d0: ``int``\n"
+        ":param d1: number of subdivisions in direction 1\n:type d1: ``int``\n"
+        ":param d2: number of subdivisions in direction 2\n:type d2: ``int``"
+        ":param multiplier: size of overlap\n:type multiplier: ``unsigned int``");
 
     def("readBinaryGrid", &ripley::readBinaryGrid, (arg("filename"),
                 arg("functionspace"), arg("shape"), arg("fill")=0.,
                 arg("byteOrder"), arg("dataType"), arg("first"),
                 arg("numValues"), arg("multiplier"), arg("reverse")),
-"Reads a binary Grid");
+            "Reads a binary Grid");
 #ifdef USE_BOOSTIO
     def("_readBinaryGridFromZipped", &ripley::readBinaryGridFromZipped, (arg("filename"),
                 arg("functionspace"), arg("shape"), arg("fill")=0.,
                 arg("byteOrder"), arg("dataType"), arg("first"),
                 arg("numValues"), arg("multiplier"), arg("reverse")),
-"Reads a binary Grid");
+            "Reads a binary Grid");
 #endif
     def("_readNcGrid", &ripley::readNcGrid, (arg("filename"), arg("varname"),
                 arg("functionspace"), arg("shape"), arg("fill"), arg("first"),
                 arg("numValues"), arg("multiplier"), arg("reverse")),
-"Reads a grid from a netCDF file");
+            "Reads a grid from a netCDF file");
 
     class_<ripley::RipleyDomain, bases<escript::AbstractContinuousDomain>, boost::noncopyable >
         ("RipleyDomain", "", no_init)
@@ -379,31 +585,32 @@ BOOST_PYTHON_MODULE(ripleycpp)
         .def("dump", &ripley::RipleyDomain::dump, args("filename"),
                 "Dumps the mesh to a file with the given name.")
         .def("getGridParameters", &ripley::RipleyDomain::getGridParameters,
-"Returns the tuple (origin, spacing, elements) where the entries are tuples:\n"
-"``origin``=the coordinates of the domain's global origin,\n"
-"``spacing``=the element size (=node spacing) of the domain,\n"
-"``elements``=the global number of elements in all dimensions\n\n"
-":rtype: ``tuple``")
+            "Returns the tuple (origin, spacing, elements) where the entries are tuples containing\n"
+            "    ``origin``  the coordinates of the domain's global origin,\n"
+            "    ``spacing``  the element size (node spacing) of the domain,\n"
+            "    ``elements``  the global number of elements in all dimensions\n\n"
+            ":rtype: ``tuple``")
         .def("getDescription", &ripley::RipleyDomain::getDescription,
-":return: a description for this domain\n:rtype: ``string``")
+            ":return: a description for this domain\n:rtype: ``string``")
         .def("getDim", &ripley::RipleyDomain::getDim, ":rtype: ``int``")
         .def("getDataShape", &ripley::RipleyDomain::getDataShape, args("functionSpaceCode"),
-":return: a pair (dps, ns) where dps=the number of data points per sample, and ns=the number of samples\n:rtype: ``tuple``")
+            ":return: a pair (dps, ns) where dps is the number of data points per sample, and ns is the number of samples\n"
+            ":rtype: ``tuple``")
         .def("getNumDataPointsGlobal", &ripley::RipleyDomain::getNumDataPointsGlobal,
-":return: the number of data points summed across all MPI processes\n"
-":rtype: ``int``")
+            ":return: the number of data points summed across all MPI processes\n"
+            ":rtype: ``int``")
         .def("addToSystem",&ripley::RipleyDomain::addToSystemFromPython,
             args("mat", "rhs", "data"),
             "adds a PDE to the system, results depend on domain\n\n"
             ":param mat:\n:type mat: `OperatorAdapter`\n"
             ":param rhs:\n:type rhs: `Data`\n"
-            ":param data:\ntype data: `list`")
+            ":param data:\n:type data: `list`\n")
         .def("addToRHS",&ripley::RipleyDomain::addToRHSFromPython,
             args("rhs", "data"),
             "adds a PDE onto the stiffness matrix mat and a rhs, "
             "results depends on domain\n\n"
             ":param rhs:\n:type rhs: `Data`\n"
-            ":param data:\ntype data: `list`")
+            ":param data:\n:type data: `list`\n")
         .def("createAssembler", &ripley::RipleyDomain::createAssemblerFromPython,
             args("typename", "options"),
             "request from the domain an assembler of the specified type, if "
@@ -414,53 +621,53 @@ BOOST_PYTHON_MODULE(ripleycpp)
             args("tp", "source", "data"),
             ":param tp:\n:type tp: `TransportProblemAdapter`\n"
             ":param source:\n:type source: `Data`\n"
-            ":param data:\ntype data: `list`")
+            ":param data:\n:type data: `list`\n")
         .def("newOperator",&ripley::RipleyDomain::newSystemMatrix,
-args("row_blocksize", "row_functionspace", "column_blocksize", "column_functionspace", "type"),
-"creates a SystemMatrixAdapter stiffness matrix and initializes it with zeros\n\n"
-":param row_blocksize:\n:type row_blocksize: ``int``\n"
-":param row_functionspace:\n:type row_functionspace: `FunctionSpace`\n"
-":param column_blocksize:\n:type column_blocksize: ``int``\n"
-":param column_functionspace:\n:type column_functionspace: `FunctionSpace`\n"
-":param type:\n:type type: ``int``"
-)
+            args("row_blocksize", "row_functionspace", "column_blocksize", "column_functionspace", "type"),
+            "creates a SystemMatrixAdapter stiffness matrix and initializes it with zeros\n\n"
+            ":param row_blocksize:\n:type row_blocksize: ``int``\n"
+            ":param row_functionspace:\n:type row_functionspace: `FunctionSpace`\n"
+            ":param column_blocksize:\n:type column_blocksize: ``int``\n"
+            ":param column_functionspace:\n:type column_functionspace: `FunctionSpace`\n"
+            ":param type:\n:type type: ``int``"
+            )
         .def("newTransportProblem",&ripley::RipleyDomain::newTransportProblem,
-args("theta", "blocksize", "functionspace", "type"),
-"creates a TransportProblemAdapter\n\n"
-":param theta:\n:type theta: ``float``\n"
-":param blocksize:\n:type blocksize: ``int``\n"
-":param functionspace:\n:type functionspace: `FunctionSpace`\n"
-":param type:\n:type type: ``int``"
-)
+            args("theta", "blocksize", "functionspace", "type"),
+            "creates a TransportProblemAdapter\n\n"
+            ":param theta:\n:type theta: ``float``\n"
+            ":param blocksize:\n:type blocksize: ``int``\n"
+            ":param functionspace:\n:type functionspace: `FunctionSpace`\n"
+            ":param type:\n:type type: ``int``"
+            )
         .def("getSystemMatrixTypeId",&ripley::RipleyDomain::getSystemMatrixTypeId,
-args("options"),
-":return: the identifier of the matrix type to be used for the global stiffness matrix when particular solver options are used.\n"
-":rtype: ``int``\n"
-":param options:\n:type options: `SolverBuddy`\n"
-)
+            args("options"),
+            ":return: the identifier of the matrix type to be used for the global stiffness matrix when particular solver options are used.\n"
+            ":rtype: ``int``\n"
+            ":param options:\n:type options: `SolverBuddy`\n"
+            )
         .def("getTransportTypeId",&ripley::RipleyDomain::getTransportTypeId,
-args("solver", "preconditioner", "package", "symmetry"),
-":return: the identifier of the transport problem type to be used when a particular solver, preconditioner, package and symmetric matrix is used.\n"
-":rtype: ``int``\n"
-":param solver:\n:type solver: ``int``\n"
-":param preconditioner:\n:type preconditioner: ``int``\n"
-":param package:\n:type package: ``int``\n"
-":param symmetry:\n:type symmetry: ``int``"
-)
+            args("solver", "preconditioner", "package", "symmetry"),
+            ":return: the identifier of the transport problem type to be used when a particular solver, preconditioner, package and symmetric matrix is used.\n"
+            ":rtype: ``int``\n"
+            ":param solver:\n:type solver: ``int``\n"
+            ":param preconditioner:\n:type preconditioner: ``int``\n"
+            ":param package:\n:type package: ``int``\n"
+            ":param symmetry:\n:type symmetry: ``int``"
+            )
         .def("getX",&ripley::RipleyDomain::getX, ":return: locations in the FEM nodes\n\n"
-":rtype: `Data`")
+            ":rtype: `Data`")
         .def("getNormal",&ripley::RipleyDomain::getNormal,
-":return: boundary normals at the quadrature point on the face elements\n"
-":rtype: `Data`")
+            ":return: boundary normals at the quadrature point on the face elements\n"
+            ":rtype: `Data`")
         .def("getSize",&ripley::RipleyDomain::getSize,":return: the element size\n"
-":rtype: `Data`")
+            ":rtype: `Data`")
         .def("setTagMap",&ripley::RipleyDomain::setTagMap,args("name","tag"),
-"Give a tag number a name.\n\n:param name: Name for the tag\n:type name: ``string``\n"
-":param tag: numeric id\n:type tag: ``int``\n:note: Tag names must be unique within a domain")
+            "Give a tag number a name.\n\n:param name: Name for the tag\n:type name: ``string``\n"
+            ":param tag: numeric id\n:type tag: ``int``\n:note: Tag names must be unique within a domain")
         .def("getTag",&ripley::RipleyDomain::getTag,args("name"),":return: tag id for "
-"``name``\n:rtype: ``string``")
+            "``name``\n:rtype: ``string``")
         .def("isValidTagName",&ripley::RipleyDomain::isValidTagName,args("name"),
-":return: True if ``name`` corresponds to a tag, otherwise False\n:rtype: ``bool``")
+            ":return: True if ``name`` corresponds to a tag, otherwise False\n:rtype: ``bool``")
         .def("showTagNames",&ripley::RipleyDomain::showTagNames,":return: A space separated list of tag names\n:rtype: ``string``")
         .def("getMPISize",&ripley::RipleyDomain::getMPISize,":return: the number of processes used for this `Domain`\n:rtype: ``int``")
         .def("getMPIRank",&ripley::RipleyDomain::getMPIRank,":return: the rank of this process\n:rtype: ``int``")
@@ -470,6 +677,8 @@ args("solver", "preconditioner", "package", "symmetry"),
      * This change became necessary when the Brick and Rectangle constructors turned into factories instead of classes */
     class_<ripley::Brick, bases<ripley::RipleyDomain> >("RipleyBrick", "", no_init);
     class_<ripley::Rectangle, bases<ripley::RipleyDomain> >("RipleyRectangle", "", no_init);
+    class_<ripley::MultiRectangle, bases<ripley::RipleyDomain> >("RipleyMultiRectangle", "", no_init);
+    class_<ripley::MultiBrick, bases<ripley::RipleyDomain> >("RipleyMultiBrick", "", no_init);
     class_<ripley::AbstractAssembler, ripley::Assembler_ptr, boost::noncopyable >
         ("AbstractAssembler", "", no_init);
 }
diff --git a/ripley/src/system_dep.h b/ripley/src/system_dep.h
index 86a6a46..90bd80e 100644
--- a/ripley/src/system_dep.h
+++ b/ripley/src/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -17,20 +17,7 @@
 #ifndef __RIPLEY_SYSTEM_DEP_H__
 #define __RIPLEY_SYSTEM_DEP_H__
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/*
- * The Intel compiler on windows has an "improved" math library compared to
- * the usual Visual C++ one. In particular it has acosh and other similar
- * functions which aren't implemented in Visual C++ math.h.
- * Note you will get a compile time error if any other header (including
- * system ones) includes math.h whilst mathimf.h has been included.
- * As a result system_dep.h must be included FIRST at all times (this
- * prevents math.h from being included).
- */
-#   include <mathimf.h>
-#else
-#   include <cmath>
-#endif
+#include <cmath>
 
 #define RIPLEY_DLL_API
 
diff --git a/ripley/test/SConscript b/ripley/test/SConscript
index e49bff6..3241ef1 100644
--- a/ripley/test/SConscript
+++ b/ripley/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/ripley/test/SystemMatrixTestCase.cpp b/ripley/test/SystemMatrixTestCase.cpp
index 3bbc75e..c86ff76 100644
--- a/ripley/test/SystemMatrixTestCase.cpp
+++ b/ripley/test/SystemMatrixTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/test/SystemMatrixTestCase.h b/ripley/test/SystemMatrixTestCase.h
index bc990c1..200d4e7 100644
--- a/ripley/test/SystemMatrixTestCase.h
+++ b/ripley/test/SystemMatrixTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/ripley/test/python/SConscript b/ripley/test/python/SConscript
index ca79bb2..013fd45 100644
--- a/ripley/test/python/SConscript
+++ b/ripley/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -39,6 +39,8 @@ env.Alias('py_tests', [os.path.splitext(x)[0]+'.passed' for x in testruns])
 program = local_env.RunPyUnitTest(testruns)
 Depends(program, py_wrapper_lib)
 Depends(program, 'build_py_tests')
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # Add a group of tests
 from grouptest import *
diff --git a/ripley/test/python/run_customAssemblersOnMultiRes.py b/ripley/test/python/run_customAssemblersOnMultiRes.py
new file mode 100644
index 0000000..a1c2b4b
--- /dev/null
+++ b/ripley/test/python/run_customAssemblersOnMultiRes.py
@@ -0,0 +1,83 @@
+
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+from __future__ import print_function
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+import esys.escriptcore.utestselect as unittest
+from esys.escriptcore.testing import *
+from esys.escript import *
+from esys.ripley import MultiResolutionDomain
+from esys.escript.linearPDEs import LameEquation
+
+from run_customAssemblersOnRipley import RipleyLameAssemblerTestBase, RipleyWaveAssemblerTestBase, Ricker
+
+mpiSize = getMPISizeWorld()
+
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
+
+class Test_RipleyWaveAssembler2D(RipleyWaveAssemblerTestBase):
+    def setUp(self):
+        self.domain = Rectangle(n0=20,n1=20,l0=100.,l1=100., diracTags=["source"],
+                diracPoints=[(0,0)])
+        self.wavelet = Ricker(100.)
+
+        
+    def tearDown(self):
+        del self.domain
+
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+class Test_RipleyWaveAssembler3D(RipleyWaveAssemblerTestBase):
+    def setUp(self):
+        self.domain = Brick(n0=10,n1=10,n2=10,l0=100.,l1=100., l2=100.,
+                diracTags=["source"], diracPoints=[(0,0,0)])
+        self.wavelet = Ricker(100.)
+
+    def tearDown(self):
+        del self.domain
+
+
+class Test_RipleyLameAssemblers2D(RipleyLameAssemblerTestBase):
+    def setUp(self):
+        self.domain = Rectangle(n0=20,n1=20)
+
+    def tearDown(self):
+        del self.domain
+
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+class Test_RipleyLameAssemblers3D(RipleyLameAssemblerTestBase):
+    def setUp(self):
+        self.domain = Brick(n0=10,n1=10,n2=10)
+
+    def tearDown(self):
+        del self.domain
+
+
+if __name__ == '__main__':
+    run_tests(__name__, exit_on_failure=True)
+
diff --git a/ripley/test/python/run_customAssemblersOnRipley.py b/ripley/test/python/run_customAssemblersOnRipley.py
index 3c238ae..bbd6cb5 100644
--- a/ripley/test/python/run_customAssemblersOnRipley.py
+++ b/ripley/test/python/run_customAssemblersOnRipley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,9 +14,9 @@
 #
 ##############################################################################
 
-from __future__ import print_function
+from __future__ import print_function, division
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -27,11 +27,242 @@ import esys.escriptcore.utestselect as unittest
 from esys.escriptcore.testing import *
 from esys.escript import *
 from esys.ripley import Rectangle, Brick
-from esys.escript.linearPDEs import LameEquation
+from esys.escript.linearPDEs import LameEquation, LinearPDESystem, WavePDE
+from esys.downunder import HTIWave, VTIWave, Ricker
 
 EXPANDED, SCALAR, CONSTANT = range(3)
 
-class RipleyCustomAssemblerTestBase(unittest.TestCase): #requires subclassing
+class RipleyWaveAssemblerTestBase(unittest.TestCase):
+    def generate_fast_HTI_PDE_solution(self):
+        pde = WavePDE(self.domain, [("c11", self.c11),
+                    ("c23", self.c23), ("c13", self.c13), ("c33", self.c33),
+                    ("c44", self.c44), ("c66", self.c66)])
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+        dim = pde.getDim()
+        X = self.domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(self.domain))
+        du = grad(X*X)
+#        D = Scalar(2500., Function(self.domain))*kronecker(dim)
+        D = 2500.*kronecker(dim)
+
+        pde.setValue(D=D, y_dirac=y, du=du)
+        return pde.getSolution()
+
+    def generate_slow_HTI_PDE_solution(self):
+        pde = LinearPDESystem(self.domain)
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+
+        dim = pde.getDim()
+        X = self.domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(self.domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+        pde.setValue(X=pde.createCoefficient('X'))
+        sigma = pde.getCoefficient('X')
+        if dim == 3:
+            e11=du[0,0]
+            e22=du[1,1]
+            e33=du[2,2]
+
+            sigma[0,0]=self.c11*e11+self.c13*(e22+e33)
+            sigma[1,1]=self.c13*e11+self.c33*e22+self.c23*e33
+            sigma[2,2]=self.c13*e11+self.c23*e22+self.c33*e33
+
+            s=self.c44*(du[2,1]+du[1,2])
+            sigma[1,2]=s
+            sigma[2,1]=s
+
+            s=self.c66*(du[2,0]+du[0,2])
+            sigma[0,2]=s
+            sigma[2,0]=s
+
+            s=self.c66*(du[0,1]+du[1,0])
+            sigma[0,1]=s
+            sigma[1,0]=s
+
+        else:
+            e11=du[0,0]
+            e22=du[1,1]
+            sigma[0,0]=self.c11*e11+self.c13*e22
+            sigma[1,1]=self.c13*e11+self.c33*e22
+
+            s=self.c66*(du[1,0]+du[0,1])
+            sigma[0,1]=s
+            sigma[1,0]=s
+
+        pde.setValue(D=D, X=-sigma, y_dirac=y)
+        return pde.getSolution()
+
+    def generate_fast_VTI_PDE_solution(self):
+        pde = WavePDE(self.domain, [("c11", self.c11),
+                    ("c12", self.c12), ("c13", self.c13), ("c33", self.c33),
+                    ("c44", self.c44), ("c66", self.c66)])
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+        dim = pde.getDim()
+
+        X = self.domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(self.domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+
+        pde.setValue(D=D, y_dirac=y, du=du)
+        return pde.getSolution()
+
+    def generate_slow_VTI_PDE_solution(self):
+        pde = LinearPDESystem(self.domain)
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+        dim = pde.getDim()
+
+        dim = pde.getDim()
+        X = self.domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(self.domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+        pde.setValue(X=pde.createCoefficient('X'))
+        sigma = pde.getCoefficient('X')
+        
+        if dim == 3:
+            e11=du[0,0]
+            e22=du[1,1]
+            e33=du[2,2]
+            sigma[0,0]=self.c11*e11+self.c12*e22+self.c13*e33
+            sigma[1,1]=self.c12*e11+self.c11*e22+self.c13*e33
+            sigma[2,2]=self.c13*(e11+e22)+self.c33*e33
+
+            s=self.c44*(du[2,1]+du[1,2])
+            sigma[1,2]=s
+            sigma[2,1]=s             
+
+            s=self.c44*(du[2,0]+du[0,2])
+            sigma[0,2]=s
+            sigma[2,0]=s
+
+            s=self.c66*(du[0,1]+du[1,0])
+            sigma[0,1]=s
+            sigma[1,0]=s
+        else:
+            e11=du[0,0]
+            e22=du[1,1]
+            sigma[0,0]=self.c11*e11+self.c13*e22
+            sigma[1,1]=self.c13*e11+self.c33*e22
+            s=self.c44*(du[1,0]+du[0,1])
+            sigma[0,1]=s
+            sigma[1,0]=s
+
+        pde.setValue(D=D, X=-sigma, y_dirac=y)
+        return pde.getSolution()
+
+    def run_HTI_assembly(self):
+        model = HTIWave(self.domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True,
+                disable_fast_assemblers=True)
+        self.assertFalse(model.fastAssembler) #ensure the arg is obeyed
+
+        model = HTIWave(self.domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True)
+        self.assertTrue(model.fastAssembler) #ensure fast is actually used
+
+        slow = self.generate_slow_HTI_PDE_solution()
+        fast = self.generate_fast_HTI_PDE_solution()
+
+        self.assertLess(Lsup(fast - slow), 1e-12) #comparison between them
+
+    def run_VTI_assembly(self):
+        model = VTIWave(self.domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True,
+                disable_fast_assemblers=True)
+        self.assertFalse(model.fastAssembler) #ensure the arg is obeyed
+
+        model = VTIWave(self.domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True)
+        self.assertTrue(model.fastAssembler) #ensure fast is actually used
+        
+        slow = self.generate_slow_VTI_PDE_solution()
+        fast = self.generate_fast_VTI_PDE_solution()
+
+        self.assertLess(Lsup(fast - slow), 1e-12) #comparison between them
+
+    def test_Function_params(self):
+        self.V_p = Data(2500., (), Function(self.domain))
+        self.V_s = Data(1250., (), Function(self.domain))
+        self.c11 = Data(11., (), Function(self.domain))
+        self.c12 = Data(12., (), Function(self.domain))
+        self.c13 = Data(13., (), Function(self.domain))
+        self.c23 = Data(23., (), Function(self.domain))
+        self.c33 = Data(33., (), Function(self.domain))
+        self.c44 = Data(44., (), Function(self.domain))
+        self.c66 = Data(66., (), Function(self.domain))
+        for i in [self.V_p, self.V_s, self.c11, self.c12, self.c13, self.c23,
+                self.c33, self.c44, self.c66]:
+            i.expand()
+        self.run_HTI_assembly()
+        self.run_VTI_assembly()
+    
+    def test_ReducedFunction_params(self):
+        self.V_p = Data(2500., (), ReducedFunction(self.domain))
+        self.V_s = Data(1250., (), ReducedFunction(self.domain))
+        self.c11 = Data(11., (), ReducedFunction(self.domain))
+        self.c12 = Data(12., (), ReducedFunction(self.domain))
+        self.c13 = Data(13., (), ReducedFunction(self.domain))
+        self.c23 = Data(23., (), ReducedFunction(self.domain))
+        self.c33 = Data(33., (), ReducedFunction(self.domain))
+        self.c44 = Data(44., (), ReducedFunction(self.domain))
+        self.c66 = Data(66., (), ReducedFunction(self.domain))
+        for i in [self.V_p, self.V_s, self.c11, self.c12, self.c13, self.c23,
+                self.c33, self.c44, self.c66]:
+            i.expand()
+        with self.assertRaises(RuntimeError) as e:
+            self.run_HTI_assembly()
+        self.assertTrue("mismatching function spaces" in str(e.exception))
+        with self.assertRaises(RuntimeError) as e:
+            self.run_VTI_assembly()
+        self.assertTrue("mismatching function spaces" in str(e.exception))
+
+    def test_Constant_params(self):
+        self.V_p = Scalar(2500., Function(self.domain))
+        self.V_s = Scalar(1250., Function(self.domain))
+        self.c11 = Scalar(11., ReducedFunction(self.domain))
+        self.c12 = Scalar(12., ReducedFunction(self.domain))
+        self.c13 = Scalar(13., ReducedFunction(self.domain))
+        self.c23 = Scalar(23., ReducedFunction(self.domain))
+        self.c33 = Scalar(33., ReducedFunction(self.domain))
+        self.c44 = Scalar(44., ReducedFunction(self.domain))
+        self.c66 = Scalar(66., ReducedFunction(self.domain))
+        with self.assertRaises(RuntimeError) as e:
+            self.run_HTI_assembly()
+        self.assertTrue("mismatching function spaces" in str(e.exception))
+        with self.assertRaises(RuntimeError) as e:
+            self.run_VTI_assembly()
+        self.assertTrue("mismatching function spaces" in str(e.exception))
+
+class Test_RipleyWaveAssembler2D(RipleyWaveAssemblerTestBase):
+    def setUp(self):
+        self.domain = Rectangle(20,20,l0=100.,l1=100., diracTags=["source"],
+                diracPoints=[(0,0)])
+        self.wavelet = Ricker(100.)
+        
+    def tearDown(self):
+        del self.domain
+
+class Test_RipleyWaveAssembler3D(RipleyWaveAssemblerTestBase):
+    def setUp(self):
+        self.domain = Brick(10,10,10,l0=100.,l1=100., l2=100.,
+                diracTags=["source"], diracPoints=[(0,0,0)])
+        self.wavelet = Ricker(100.)
+
+    def tearDown(self):
+        del self.domain
+
+
+class RipleyLameAssemblerTestBase(unittest.TestCase): #requires subclassing
     def run_lame(self, fast, test_type, mu=3, lamb=50):
         d=self.domain.getDim()
         mypde=LameEquation(self.domain, useFast=fast)
@@ -92,14 +323,14 @@ class RipleyCustomAssemblerTestBase(unittest.TestCase): #requires subclassing
                 "Default and Lame %dDassembler solutions differ for "\
                 "constant data"%self.domain.getDim())
 
-class Test_RipleyCustomAssemblers2D(RipleyCustomAssemblerTestBase):
+class Test_RipleyLameAssemblers2D(RipleyLameAssemblerTestBase):
     def setUp(self):
         self.domain = Rectangle(20,20)
 
     def tearDown(self):
         del self.domain
 
-class Test_RipleyCustomAssemblers3D(RipleyCustomAssemblerTestBase):
+class Test_RipleyLameAssemblers3D(RipleyLameAssemblerTestBase):
     def setUp(self):
         self.domain = Brick(10,10,10)
 
diff --git a/ripley/test/python/run_diracOnMultiRes.py b/ripley/test/python/run_diracOnMultiRes.py
new file mode 100644
index 0000000..42f6396
--- /dev/null
+++ b/ripley/test/python/run_diracOnMultiRes.py
@@ -0,0 +1,142 @@
+
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+from __future__ import print_function, division
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+import os, sys
+import esys.escriptcore.utestselect as unittest
+from esys.escriptcore.testing import *
+from esys.escript import *
+from esys.escript.linearPDEs import LameEquation
+from esys.ripley import MultiResolutionDomain
+from run_diracOnRipley import Test_RipleyDiracPoints
+
+mpiSize = getMPISizeWorld()
+
+try:
+     RIPLEY_WORKDIR=os.environ['RIPLEY_WORKDIR']
+except KeyError:
+     RIPLEY_WORKDIR='.'
+
+brickLevel = 2
+rectLevel = 2
+
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(rectLevel - 1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(brickLevel - 1)
+
+ at unittest.skipIf(mpiSize > 1, "Multiresolution domains require single process")
+class Test_DiracPointsOnMultiResolutionDomains(Test_RipleyDiracPoints):
+
+    def setup(self):
+        # constants
+        self.numRanks = getMPISizeWorld()
+        self.rank = getMPIRankWorld()
+        self.shortEdge = 3
+        self.longFactor = 5
+        self.longEdge = self.longFactor*self.numRanks-1
+        self.empty = "(data contains no samples)\n"
+
+    def getRectRefs(self, xLong):
+        Ex = self.longEdge+1
+        Ey = self.shortEdge+1
+        if not xLong:
+            Ex, Ey = Ey, Ex
+        result = [[-1 for j in range(Ex)] for i in range(Ey)]
+        ref = 0
+        if xLong:
+            for rankx in range(self.numRanks):
+                for y in range(Ey):
+                    for x in range(self.longFactor):
+                        old = [ref%Ex, ref//Ex]
+                        new = [i*rectLevel for i in old]
+                        node = new[0] + new[1]*(rectLevel*Ex-1)
+                        result[y][x+self.longFactor*rankx] = node
+                        ref += 1
+        else:
+            for y in range(Ey):
+                for x in range(Ex):
+                    old = [ref%Ex, ref//Ex]
+                    new = [i*rectLevel for i in old]
+                    node = new[0] + new[1]*(rectLevel*Ex-1)
+                    result[y][x] = node
+                    ref += 1
+        return result
+            
+    def getBrickRefs(self, splitAxis, dims):
+        dims = [i+1 for i in dims]
+        results = [[[-1 for z in range(dims[2])] for y in range(dims[1])] for x in range(dims[0])]
+        ref = 0
+        rankDim = [i for i in dims]
+        rankDim[splitAxis] = dims[splitAxis]//self.numRanks
+        rc = [0, 0, 0] #rank counters
+        for rank in range(self.numRanks):
+            for z in range(rankDim[2]):
+                for y in range(rankDim[1]):
+                    for x in range(rankDim[0]):
+                        old = [ref%dims[0], (ref%(dims[0]*dims[1]))//dims[0], ref//(dims[0]*dims[1])]
+                        new = [i*brickLevel for i in old]
+                        node = new[0] + new[1]*(brickLevel*(dims[0]-1)+1) + new[2]*(brickLevel*(dims[0]-1) + 1)*(brickLevel*(dims[1]-1)+1)
+                        results[x+rc[0]][y+rc[1]][z+rc[2]] = node
+                        ref += 1
+            rc[splitAxis] += rankDim[splitAxis]
+        return results
+
+    def generateRects(self, a, b):
+        diracLoc = [a,b]
+        edges = [self.longEdge, self.shortEdge]
+        rects = []
+        for i in range(2):
+            rects.append(Rectangle(n0=edges[0], n1=edges[1],
+                      l0=edges[0], l1=edges[1],
+                      d0=self.numRanks, diracPoints=[tuple(diracLoc)],
+                      diracTags=["test"]))
+            diracLoc = diracLoc[::-1]
+            edges = edges[::-1]
+        return rects
+
+    def generateBricks(self, a, b, c):
+        diracLoc = [a,b,c]
+        bricks = []
+        edges = [self.longEdge, self.shortEdge, self.shortEdge]
+        for i in range(3):
+            bricks.append(Brick(n0=edges[0], n1=edges[1], n2=edges[2],
+                l0=edges[0], l1=edges[1], l2=edges[2],
+                d0=self.numRanks,
+                diracPoints=[tuple(diracLoc)], diracTags=["test"]))
+            diracLoc = diracLoc[2:] + diracLoc[:2]
+            edges = edges[2:] + edges[:2]
+        tmp = [self.shortEdge]*3
+        dims = [tmp[:], tmp[:], tmp[:]]
+        for i in range(3):
+            dims[i][i] = self.longEdge
+        return bricks, dims
+
+if __name__ == '__main__':
+    run_tests(__name__, exit_on_failure=True)
+
+
diff --git a/ripley/test/python/run_diracOnRipley.py b/ripley/test/python/run_diracOnRipley.py
index 6c0608a..bea1af8 100644
--- a/ripley/test/python/run_diracOnRipley.py
+++ b/ripley/test/python/run_diracOnRipley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function, division
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -37,12 +37,7 @@ except KeyError:
 
 class Test_RipleyDiracPoints(unittest.TestCase):
 
-    # constants
-    numRanks = getMPISizeWorld()
-    rank = getMPIRankWorld()
-    shortEdge = 5
-    longEdge = 3*numRanks-1
-    empty = "(data contains no samples)\n"
+
 
     def getRectRefs(self, xLong):
         Ex = self.longEdge+1
@@ -137,7 +132,13 @@ class Test_RipleyDiracPoints(unittest.TestCase):
         return self.empty
 
     def setUp(self):
-        pass
+        # constants
+        self.numRanks = getMPISizeWorld()
+        self.rank = getMPIRankWorld()
+        self.shortEdge = 5
+        self.longFactor = 3
+        self.longEdge = self.longFactor*self.numRanks-1
+        self.empty = "(data contains no samples)\n"
 
     def tearDown(self):
         pass
diff --git a/ripley/test/python/run_escriptOnMultiResolution.py b/ripley/test/python/run_escriptOnMultiResolution.py
new file mode 100644
index 0000000..b750ed8
--- /dev/null
+++ b/ripley/test/python/run_escriptOnMultiResolution.py
@@ -0,0 +1,395 @@
+
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+import os
+import sys
+import esys.escriptcore.utestselect as unittest
+from esys.escriptcore.testing import *
+from esys.escript import *
+from esys.ripley import MultiRectangle, MultiBrick, ripleycpp, MultiResolutionDomain
+from test_objects import Test_Dump, Test_SetDataPointValue, Test_saveCSV, Test_TableInterpolation
+from test_objects import Test_Domain, Test_GlobalMinMax, Test_Lazy
+
+from test_shared import Test_Shared
+
+from run_escriptOnRipley import Test_SharedOnRipley, Test_DomainOnRipley, \
+                        Test_TableInterpolationOnRipley, Test_DataOpsOnRipley, \
+                        Test_CSVOnRipley
+
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
+
+
+try:
+     RIPLEY_WORKDIR=os.environ['RIPLEY_WORKDIR']
+except KeyError:
+     RIPLEY_WORKDIR='.'
+
+NE=4 # number elements, must be even
+mpiSize=getMPISizeWorld()
+for x in [int(sqrt(mpiSize)),2,3,5,7,1]:
+    NX=x
+    NY=mpiSize//x
+    if NX*NY == mpiSize:
+        break
+
+for x in [(int(mpiSize**(1/3.)),int(mpiSize**(1/3.))),(2,3),(2,2),(1,2),(1,1)]:
+    NXb=x[0]
+    NYb=x[1]
+    NZb=mpiSize//(x[0]*x[1])
+    if NXb*NYb*NZb == mpiSize:
+        break
+
+class Test_SharedOnMultiRipley(Test_SharedOnRipley):
+    def setUp(self):
+        self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.tol=0.001
+
+    def tearDown(self):
+        del self.domain
+        del self.tol
+
+class Test_DomainOnMultiRipley(Test_DomainOnRipley):
+    def setUp(self):
+        self.boundary_tag_list = [1, 2, 10, 20]
+        self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.rdomain=Rectangle(n0=(NE+6)*NX-1, n1=(NE+6)*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+
+    def tearDown(self):
+        del self.domain
+        del self.boundary_tag_list
+
+class Test_DataOpsOnMultiRipley(Test_DataOpsOnRipley):
+    def setUp(self):
+        self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.domain_with_different_number_of_samples=Rectangle(n0=7*NE*NX-1, n1=3*NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.domain_with_different_number_of_data_points_per_sample=Rectangle(n0=7*NE*NX-1, n1=3*NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.domain_with_different_sample_ordering=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.filename_base=RIPLEY_WORKDIR
+        self.mainfs=Function(self.domain)
+        self.otherfs=Solution(self.domain)
+
+    def tearDown(self):
+        del self.domain
+        del self.domain_with_different_number_of_samples
+        del self.domain_with_different_number_of_data_points_per_sample
+        del self.domain_with_different_sample_ordering
+        del self.mainfs
+        del self.otherfs
+
+ at unittest.skipIf(mpiSize > 1, "Multiresolution domains require single process")
+class Test_TableInterpolationOnMultiRipley(Test_TableInterpolationOnRipley):
+    def setUp(self):
+        self.domain = Brick(n0=NE*NXb-1, n1=NE*NYb-1, n2=NE*NZb-1, l0=1., l1=1., l2=1., d0=NXb, d1=NYb, d2=NZb)
+        self.functionspaces=[ContinuousFunction(self.domain), Function(self.domain), ReducedFunction(self.domain),
+            FunctionOnBoundary(self.domain), ReducedFunctionOnBoundary(self.domain)]
+        #We aren't testing DiracDeltaFunctions
+        self.xn=5 # number of grids on x axis
+        self.yn=5 # number of grids on y axis
+        self.zn=5
+
+    def tearDown(self):
+        del self.domain
+        del self.functionspaces
+
+class Test_CSVOnMultiRipley(Test_CSVOnRipley):
+    def setUp(self):
+        self.workdir=RIPLEY_WORKDIR
+        self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
+        self.functionspaces=[ContinuousFunction, Function, ReducedFunction,
+                             FunctionOnBoundary, ReducedFunctionOnBoundary]
+
+        NE0 = (NE*NX-1)*2
+        NE1 = (NE*NY-1)*2
+
+        # number of total data points for each function space
+        self.linecounts=[ (NE0+1)*(NE1+1)+1, 4*NE0*NE1+1, NE0*NE1+1,
+                4*NE0+4*NE1+1, 2*NE0+2*NE1+1 ]
+        # number of masked points, i.e. where X[0] is non-zero
+        self.linecounts_masked=[ NE0*(NE1+1)+1, 4*NE0*NE1+1, NE0*NE1+1,
+                4*NE0+2*NE1+1, 2*NE0+NE1+1 ]
+        # expected values in first line of masked data = [ X[:], X[0] ]
+        self.firstline=[ [1./NE0, 0., 1./NE0],
+                         [None, None, None],
+                         [None, None, None],
+                         [None, None, None],
+                         [None, None, None] ]
+
+    def tearDown(self):
+        del self.domain
+
+
+class Test_randomOnMultiRipley(unittest.TestCase):
+    def test_FillRectangle(self):
+        fs=ContinuousFunction(Rectangle(n0=5*(int(sqrt(mpiSize)+1)),n1=5*(int(sqrt(mpiSize)+1))))
+        RandomData((), fs, 2,("gaussian",1,0.5))
+        RandomData((), fs, 0,("gaussian",2,0.76))
+        self.assertRaises(RuntimeError, RandomData, (2,2), fs, 0, ("gaussian",2,0.76)) #data not scalar
+        self.assertRaises(RuntimeError, RandomData, (), fs, 0, ("gaussian",11,0.1)) #radius too large
+        RandomData((2,3),fs)
+
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_FillBrick(self):
+        # If we are going to do really big tests of this, the size of this brick will need to be reduced
+        fs=ContinuousFunction(Brick(n0=5*mpiSize, n1=5*mpiSize, n2=5*mpiSize))
+        RandomData((), fs, 2,("gaussian",1,0.5))
+        RandomData((), fs, 0,("gaussian",2,0.76))
+        self.assertRaises(RuntimeError, RandomData, (2,2), fs, 0, ("gaussian",2,0.76)) #data not scalar
+        self.assertRaises(RuntimeError, RandomData, (), fs, 0, ("gaussian",11,0.1)) #radius too large
+        RandomData((2,3),fs)
+
+class Test_multiResolution(unittest.TestCase):
+    def test_MultiRectangle_constructors(self):
+        with self.assertRaises(OverflowError): #negative is bad
+            MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=-1)
+        with self.assertRaises(RuntimeError): #zero is bad
+            MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=0)
+        with self.assertRaises(TypeError): #non-int is bad
+            MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=.5)
+        with self.assertRaises(RuntimeError): #non-power of two is bad
+            MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=3)
+        with self.assertRaises(Exception): #dimensions required
+            MultiRectangle(n1=5, d1=mpiSize, multiplier=3)
+        MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=1)
+        MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=2)
+        MultiRectangle(n0=2*mpiSize-1, n1=5, d0=mpiSize, multiplier=8)
+
+    def test_RectangleInterpolation_NodesToNodesAndElements_CoarseToFine(self):
+        mrd = MultiResolutionDomain(2, n0=2, n1=2*mpiSize-1, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [i.getX() for i in domains]
+
+        for targetFS, name in [(Function, 'Function'),
+                       (ContinuousFunction, 'ContinuousFunction'),
+                       (ReducedContinuousFunction, 'ReducedContinuousFunction')]:
+            for source_level in range(len(domains)):
+                for target_level in range(source_level + 1, len(domains)):
+                    val = Lsup(interpolate(X[target_level], targetFS(domains[target_level])) \
+                            - interpolate(X[source_level], targetFS(domains[target_level])))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'ContinuousFunction', source_level, name, target_level, val))
+
+    def test_RectangleInterpolation_NodesToElements_FineToCoarse(self):
+        mrd = MultiResolutionDomain(2, n0=2, n1=2*mpiSize-1, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [i.getX() for i in domains]
+
+        for targetFS, name in [(Function, 'Function')]:
+            for source_level in range(len(domains)):
+                for target_level in range(0, source_level):
+                    val = Lsup(interpolate(X[target_level], targetFS(domains[target_level])) \
+                            - interpolate(X[source_level], targetFS(domains[target_level])))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'ContinuousFunction', source_level, name, target_level, val))
+
+    def test_RectangleInterpolation_ReducedToElements_CoarseToFine(self):
+        mrd = MultiResolutionDomain(2, n0=2, n1=2*mpiSize-1, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [interpolate(i.getX(), ReducedFunction(i)) for i in domains]
+
+        for targetFS, name in [(Function, 'Function')]:
+            for source_level in range(len(domains)):
+                for target_level in range(source_level + 1, len(domains)):
+                    to = targetFS(domains[target_level])
+                    desired = interpolate(X[source_level], Function(domains[source_level]))
+                    val = Lsup(interpolate(X[source_level], to) - desired)
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'ReducedFunction', source_level, name, target_level, val))        
+
+    def test_RectangleInterpolation_ElementsToElements_CoarseToFine(self):
+        mrd = MultiResolutionDomain(2, n0=2, n1=2*mpiSize-1, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [interpolate(i.getX(), Function(i)) for i in domains]
+
+        for targetFS, name in [(Function, 'Function')]:
+            for source_level in range(len(domains)):
+                for target_level in range(source_level + 1, len(domains)):
+                    val = Lsup(interpolate(X[source_level], targetFS(domains[target_level])) \
+                            - interpolate(X[target_level], targetFS(domains[target_level])))
+                    if val > 1e-12:
+                        print("Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'Function', source_level, name, target_level, val))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'Function', source_level, name, target_level, val))
+
+    def test_RectangleInterpolation_ElementsToElements_FineToCoarse(self):
+        mrd = MultiResolutionDomain(2, n0=2, n1=2*mpiSize-1, d1=mpiSize, l0=2)
+        d0 = mrd.getLevel(0)
+        d1 = mrd.getLevel(1)
+        d2 = mrd.getLevel(2)
+        x0 = interpolate(d0.getX(), Function(d0))
+        x1 = interpolate(d1.getX(), Function(d1))
+        x2 = interpolate(d2.getX(), Function(d2))
+
+        val = Lsup(x0 - interpolate(x1, Function(d0)))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure from level 1 to level 0: %g !< 1e-12"%val)
+
+        val = Lsup(x1 - interpolate(x2, Function(d1)))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure from level 2 to level 1: %g !< 1e-12"%val)
+
+        val = Lsup(x0 - interpolate(x2, Function(d0)))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure from level 2 to level 0: %g !< 1e-12"%val)
+        
+        val = Lsup(integrate(interpolate(sin(x2[0]), Function(d0))*x0) - integrate(sin(x2[0])*x2))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure: %g !< 1e-12"%val)
+
+        val = integrate(interpolate(sin(x2[0]), Function(d0))*x0[0]*x0[1]) - integrate(sin(x2[0])*x2[0]*x2[1])
+        self.assertLess(val, 1e-12,
+                "Interpolation failure: %g !< 1e-12"%val)
+        
+        val = integrate(interpolate(sin(x2[0]), Function(d0))) - integrate(sin(x2[0]))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure: %g !< 1e-12"%val)
+
+
+
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_MultiBrick_constructors(self):
+        with self.assertRaises(OverflowError): #negative is bad
+            MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=-1)
+        with self.assertRaises(RuntimeError): #zero is bad
+            MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=0)
+        with self.assertRaises(TypeError): #non-int is bad
+            MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=.5)
+        with self.assertRaises(RuntimeError): #non-power of two is bad
+            MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=3)
+        with self.assertRaises(Exception): #dimensions required
+            MultiBrick(n1=5, n2=3, d1=mpiSize, multiplier=3)
+        MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=1)
+        MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=2)
+        MultiBrick(n0=2*mpiSize-1, n1=5, n2=3, d1=mpiSize, multiplier=8)
+
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_BrickInterpolation_NodesToNodesAndElements_CoarseToFine(self):
+        mrd = MultiResolutionDomain(3, n0=2, n1=2*mpiSize, n2=3, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [i.getX() for i in domains]
+
+        for targetFS, name in [(Function, 'Function'),
+                       (ContinuousFunction, 'ContinuousFunction'),
+                       (ReducedContinuousFunction, 'ReducedContinuousFunction')]:
+            for source_level in range(len(domains)):
+                for target_level in range(source_level + 1, len(domains)):
+                    val = Lsup(interpolate(X[target_level], targetFS(domains[target_level])) \
+                            - interpolate(X[source_level], targetFS(domains[target_level])))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'ContinuousFunction', source_level, name, target_level, val))
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_BrickInterpolation_NodesToElements_FineToCoarse(self):
+        mrd = MultiResolutionDomain(3, n0=2, n1=2*mpiSize, n2=3, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [i.getX() for i in domains]
+
+        for targetFS, name in [(Function, 'Function')]:
+            for source_level in range(len(domains)):
+                for target_level in range(0, source_level):
+                    val = Lsup(interpolate(X[target_level], targetFS(domains[target_level])) \
+                            - interpolate(X[source_level], targetFS(domains[target_level])))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'ContinuousFunction', source_level, name, target_level, val))
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_BrickInterpolation_ReducedToElements_CoarseToFine(self):
+        mrd = MultiResolutionDomain(3, n0=2, n1=2*mpiSize, n2=3, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [interpolate(i.getX(), ReducedFunction(i)) for i in domains]
+
+        for targetFS, name in [(Function, 'Function')]:
+            for source_level in range(len(domains)):
+                for target_level in range(source_level + 1, len(domains)):
+                    to = targetFS(domains[target_level])
+                    desired = interpolate(X[source_level], Function(domains[source_level]))
+                    val = Lsup(interpolate(X[source_level], to) \
+                            - interpolate(desired, to))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'ReducedFunction', source_level, name, target_level, val))        
+
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_BrickInterpolation_ElementsToElements_CoarseToFine(self):
+        mrd = MultiResolutionDomain(3, n0=2, n1=2*mpiSize, n2=2, d1=mpiSize, l0=2)
+        domains = [mrd.getLevel(i) for i in range(3)]
+        X = [interpolate(i.getX(), Function(i)) for i in domains]
+
+        for targetFS, name in [(Function, 'Function')]:
+            for source_level in range(len(domains)):
+                for target_level in range(source_level + 1, len(domains)):
+                    val = Lsup(interpolate(X[target_level], targetFS(domains[target_level])) \
+                            - interpolate(X[source_level], targetFS(domains[target_level])))
+                    self.assertLess(val, 1e-12,
+                            "Interpolation failure from %s level %d to %s level %d: %g !< 1e-12"%(\
+                            'Function', source_level, name, target_level, val))
+
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
+    def test_BrickInterpolation_ElementsToElements_FineToCoarse(self):
+        mrd = MultiResolutionDomain(3, n0=2, n1=2*mpiSize, n2=3, d1=mpiSize, l0=2)
+        d0 = mrd.getLevel(0)
+        d1 = mrd.getLevel(1)
+        d2 = mrd.getLevel(2)
+        x0 = interpolate(d0.getX(), Function(d0))
+        x1 = interpolate(d1.getX(), Function(d1))
+        x2 = interpolate(d2.getX(), Function(d2))
+
+        val = Lsup(x0 - interpolate(x1, Function(d0)))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure from level 1 to level 0: %g !< 1e-12"%val)
+
+        val = Lsup(x1 - interpolate(x2, Function(d1)))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure from level 2 to level 1: %g !< 1e-12"%val)
+
+        val = Lsup(x0 - interpolate(x2, Function(d0)))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure from level 2 to level 0: %g !< 1e-12"%val)
+        
+        val = Lsup(integrate(interpolate(sin(x2[0]), Function(d0))*x0) - integrate(sin(x2[0])*x2))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure: %g !< 1e-12"%val)
+
+        val = integrate(interpolate(sin(x2[0]), Function(d0))*x0[0]*x0[1]*x0[2]) - integrate(sin(x2[0])*x2[0]*x2[1]*x2[2])
+        self.assertLess(val, 1e-12,
+                "Interpolation failure: %g !< 1e-12"%val)
+        
+        val = integrate(interpolate(sin(x2[0]), Function(d0))) - integrate(sin(x2[0]))
+        self.assertLess(val, 1e-12,
+                "Interpolation failure: %g !< 1e-12"%val)
+
+
+
+if __name__ == '__main__':
+    run_tests(__name__, exit_on_failure=True)
+
diff --git a/ripley/test/python/run_escriptOnRipley.py b/ripley/test/python/run_escriptOnRipley.py
index 33f583c..f8f6d75 100644
--- a/ripley/test/python/run_escriptOnRipley.py
+++ b/ripley/test/python/run_escriptOnRipley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -132,6 +132,7 @@ class Test_TableInterpolationOnRipley(Test_TableInterpolation):
 
 class Test_CSVOnRipley(Test_saveCSV):
     def setUp(self):
+        self.workdir=RIPLEY_WORKDIR
         self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
         self.functionspaces=[ContinuousFunction, Function, ReducedFunction,
                              FunctionOnBoundary, ReducedFunctionOnBoundary]
@@ -176,8 +177,8 @@ class Test_randomOnRipley(unittest.TestCase):
         fs=ContinuousFunction(Rectangle(10*(int(sqrt(mpiSize)+1)),10*(int(sqrt(mpiSize)+1))))
         RandomData((), fs, 2,("gaussian",1,0.5))
         RandomData((), fs, 0,("gaussian",2,0.76))
-        self.assertRaises(RuntimeError, RandomData, (2,2), fs, 0, ("gaussian",2,0.76))
-        self.assertRaises(RuntimeError, RandomData, (), fs, 0, ("gaussian",11,0.1))
+        self.assertRaises(RuntimeError, RandomData, (2,2), fs, 0, ("gaussian",2,0.76)) #data not scalar
+        self.assertRaises(RuntimeError, RandomData, (), fs, 0, ("gaussian",11,0.1)) #radius too large
         RandomData((2,3),fs)
 
     def test_FillBrick(self):
@@ -185,8 +186,8 @@ class Test_randomOnRipley(unittest.TestCase):
         fs=ContinuousFunction(Brick(10*mpiSize,10*mpiSize, 10*mpiSize))
         RandomData((), fs, 2,("gaussian",1,0.5))
         RandomData((), fs, 0,("gaussian",2,0.76))
-        self.assertRaises(RuntimeError, RandomData, (2,2), fs, 0, ("gaussian",2,0.76))
-        self.assertRaises(RuntimeError, RandomData, (), fs, 0, ("gaussian",20,0.1))
+        self.assertRaises(RuntimeError, RandomData, (2,2), fs, 0, ("gaussian",2,0.76)) #data not scalar
+        self.assertRaises(RuntimeError, RandomData, (), fs, 0, ("gaussian",20,0.1)) #radius too large
         RandomData((2,3),fs)
 
 
diff --git a/ripley/test/python/run_linearPDEsOnRipley.py b/ripley/test/python/run_linearPDEsOnMultiRes.py
similarity index 84%
copy from ripley/test/python/run_linearPDEsOnRipley.py
copy to ripley/test/python/run_linearPDEsOnMultiRes.py
index cb967bb..9f7d907 100644
--- a/ripley/test/python/run_linearPDEsOnRipley.py
+++ b/ripley/test/python/run_linearPDEsOnMultiRes.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
@@ -40,8 +40,7 @@ from test_linearPDEs import Test_Poisson, Test_LinearPDE, Test_TransportPDE, Tes
 from test_assemblage import Test_assemblage_2Do1, Test_assemblage_3Do1
 from test_pdetools import Test_pdetools, Test_pdetools_noLumping
 from esys.escript import *
-from esys.ripley import Rectangle, Brick
-
+from esys.ripley import MultiResolutionDomain
 
 try:
      RIPLEY_TEST_DATA=os.environ['RIPLEY_TEST_DATA']
@@ -51,6 +50,15 @@ except KeyError:
 NE=10 # number of element in each spatial direction (must be even)
 mpiSize=getMPISizeWorld()
 
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
+
+
 class Test_LinearPDEOnRipleyRect(Test_LinearPDE, Test_LameEquation, Test_Helmholtz, Test_LinearPDE_noLumping, Test_pdetools, Test_assemblage_2Do1, Test_TransportPDE):
     RES_TOL=1.e-7
     ABS_TOL=1.e-8
@@ -65,6 +73,7 @@ class Test_LinearPDEOnRipleyRect(Test_LinearPDE, Test_LameEquation, Test_Helmhol
     def tearDown(self):
         del self.domain
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_LinearPDEOnRipleyBrick(Test_LinearPDE, Test_LameEquation, Test_Helmholtz, Test_LinearPDE_noLumping, Test_pdetools, Test_assemblage_3Do1, Test_TransportPDE):
     RES_TOL=1.e-7
     ABS_TOL=1.e-8
diff --git a/ripley/test/python/run_linearPDEsOnRipley.py b/ripley/test/python/run_linearPDEsOnRipley.py
index cb967bb..3ad136f 100644
--- a/ripley/test/python/run_linearPDEsOnRipley.py
+++ b/ripley/test/python/run_linearPDEsOnRipley.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/ripley/test/python/run_nonlinearPDEOnRipley.py b/ripley/test/python/run_nonlinearPDEOnMultiRes.py
similarity index 71%
copy from ripley/test/python/run_nonlinearPDEOnRipley.py
copy to ripley/test/python/run_nonlinearPDEOnMultiRes.py
index d14735f..2f00ef1 100644
--- a/ripley/test/python/run_nonlinearPDEOnRipley.py
+++ b/ripley/test/python/run_nonlinearPDEOnMultiRes.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
@@ -27,8 +27,17 @@ import esys.escriptcore.utestselect as unittest
 from esys.escriptcore.testing import *
 from test_nonLinearPDE import Test_nlpde
 from esys.escript import getMPISizeWorld
-from esys.ripley import Rectangle,Brick
+from esys.ripley import MultiResolutionDomain
 
+mpiSize = getMPISizeWorld()
+
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
 
 class Test_RipleyNonLinearPDE2D(Test_nlpde):
    def setUp(self):
@@ -36,6 +45,7 @@ class Test_RipleyNonLinearPDE2D(Test_nlpde):
    def tearDown(self):
         del self.domain
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_RipleyNonLinearPDE3D(Test_nlpde):
    def setUp(self):
         self.domain = Brick(l0=1.,l1=1.,l2=1., n0=10, n1=10*getMPISizeWorld()-1, n2=10, d1=getMPISizeWorld()) 
diff --git a/ripley/test/python/run_nonlinearPDEOnRipley.py b/ripley/test/python/run_nonlinearPDEOnRipley.py
index d14735f..0b143a8 100644
--- a/ripley/test/python/run_nonlinearPDEOnRipley.py
+++ b/ripley/test/python/run_nonlinearPDEOnRipley.py
@@ -1,7 +1,7 @@
 
 ########################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # Earth Systems Science Computational Center (ESSCC)
 # http://www.uq.edu.au
 #
@@ -11,7 +11,7 @@
 #
 ########################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 Earth Systems Science Computational Center (ESSCC)
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
diff --git a/ripley/test/python/run_readWriteOnRipley.py b/ripley/test/python/run_readWriteOnMultiRes.py
similarity index 70%
copy from ripley/test/python/run_readWriteOnRipley.py
copy to ripley/test/python/run_readWriteOnMultiRes.py
index 5edede0..5d70684 100644
--- a/ripley/test/python/run_readWriteOnRipley.py
+++ b/ripley/test/python/run_readWriteOnMultiRes.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -33,19 +33,6 @@ try:
 except KeyError:
      RIPLEY_WORKDIR='/tmp'
 
-#NE=4 # number elements, must be even
-#for x in [int(sqrt(mpiSize)),2,3,5,7,1]:
-#    NX=x
-#    NY=mpiSize//x
-#    if NX*NY == mpiSize:
-#        break
-#
-#for x in [(int(mpiSize**(1/3.)),int(mpiSize**(1/3.))),(2,3),(2,2),(1,2),(1,1)]:
-#    NXb=x[0]
-#    NYb=x[1]
-#    NZb=mpiSize//(x[0]*x[1])
-#    if NXb*NYb*NZb == mpiSize:
-#        break
 
 mpiSize = getMPISizeWorld()
 mpiRank = getMPIRankWorld()
@@ -55,7 +42,15 @@ def adjust(NE, ftype):
         return [i+1 for i in NE]
     return NE
 
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
 
+ at unittest.skipIf(mpiSize > 1, "Multiresolution domains don't support multiprocess yet")
 class WriteBinaryGridTestBase(unittest.TestCase): #subclassing required
     NX = 10*mpiSize-1
     NZ = 10
@@ -90,21 +85,23 @@ class WriteBinaryGridTestBase(unittest.TestCase): #subclassing required
 
     def test_writeGrid2D(self):
         self.NE = [self.NX, self.NZ]
-        self.domain = Rectangle(self.NE[0], self.NE[1], d1=0)
+        self.domain = Rectangle(n0=self.NE[0], n1=self.NE[1], d1=1)
         for ftype,fcode in [(ReducedFunction,'RF'), (ContinuousFunction,'CF'), (Solution, 'Sol')]:
             data, ref = self.generateUniqueData(ftype)
-            result = self.writeThenRead(data, ftype, fcode)
-            self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
-                    msg="Data doesn't match for "+str(ftype(self.domain)))
+            with self.assertRaises(RuntimeError):
+                result = self.writeThenRead(data, ftype, fcode)
+                self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
+                        msg="Data doesn't match for "+str(ftype(self.domain)))
 
     def test_writeGrid3D(self):
         self.NE = [self.NX, self.NX, self.NZ]
-        self.domain = Brick(self.NE[0], self.NE[1], self.NE[2], d2=0)
+        self.domain = Brick(n0=self.NE[0], n1=self.NE[1], n2=self.NE[2], d2=1)
         for ftype,fcode in [(ReducedFunction,'RF'), (ContinuousFunction,'CF'), (Solution, 'Sol')]:
             data, ref = self.generateUniqueData(ftype)
-            result = self.writeThenRead(data, ftype, fcode)
-            self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
-                    msg="Data doesn't match for "+str(ftype(self.domain)))
+            with self.assertRaises(RuntimeError):
+                result = self.writeThenRead(data, ftype, fcode)
+                self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
+                        msg="Data doesn't match for "+str(ftype(self.domain)))
 
 class Test_writeBinaryGridRipley_LITTLE_FLOAT32(WriteBinaryGridTestBase):
     def setUp(self):
@@ -209,7 +206,7 @@ class ReadBinaryGridTestBase(unittest.TestCase): #subclassing required
             self.NE = [self.NX*mpiSize-1, self.NZ*self.multiplier[1]]
         else:
             self.NE = [self.NX*mpiSize*self.multiplier[0]-1, self.NZ*self.multiplier[1]]
-        self.domain = Rectangle(self.NE[0], self.NE[1], d0=mpiSize, d1=1)
+        self.domain = Rectangle(n0=self.NE[0], n1=self.NE[1], d0=mpiSize, d1=1)
         for ftype,fcode in self.fspaces:
             self.Ndata = [self.NX*mpiSize-1, self.NZ]
             if ftype==ContinuousFunction:
@@ -217,40 +214,42 @@ class ReadBinaryGridTestBase(unittest.TestCase): #subclassing required
             # step 1 - generate
             ref = self.generateUniqueData(ftype)
             # step 2 & 3
-            result = self.numpy2Data2Numpy(ref, ftype, fcode)
-            # apply transformations to be able to compare
-            if self.reverse[0]:
-                result = result[...,::-1]
-            if self.reverse[1]:
-                result = result[::-1,:]
-            for i in range(2):
-                ref = np.repeat(ref, self.multiplier[i], axis=1-i)
-
-            # if domain larger than data: add column(s)/row(s) with fill value
-            fill=np.array(self.fill, dtype=ref.dtype)
-            realNE = adjust(self.NE,ftype)
-            for d in range(2):
-                excess = realNE[d]-ref.shape[1-d]
-                if excess > 0:
-                    shape = list(ref.shape)
-                    shape[1-d] = excess
-                    extra = fill * np.ones(shape)
-                    if self.reverse[d]:
-                        ref = np.append(extra, ref, axis=1-d)
-                    else:
-                        ref = np.append(ref, extra, axis=1-d)
-
-            # step 4 - compare
-            self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
-                    msg="Data doesn't match for "+str(ftype(self.domain)))
-
+            with self.assertRaises(RuntimeError):
+                result = self.numpy2Data2Numpy(ref, ftype, fcode)
+                # apply transformations to be able to compare
+                if self.reverse[0]:
+                    result = result[...,::-1]
+                if self.reverse[1]:
+                    result = result[::-1,:]
+                for i in range(2):
+                    ref = np.repeat(ref, self.multiplier[i], axis=1-i)
+
+                # if domain larger than data: add column(s)/row(s) with fill value
+                fill=np.array(self.fill, dtype=ref.dtype)
+                realNE = adjust(self.NE,ftype)
+                for d in range(2):
+                    excess = realNE[d]-ref.shape[1-d]
+                    if excess > 0:
+                        shape = list(ref.shape)
+                        shape[1-d] = excess
+                        extra = fill * np.ones(shape)
+                        if self.reverse[d]:
+                            ref = np.append(extra, ref, axis=1-d)
+                        else:
+                            ref = np.append(ref, extra, axis=1-d)
+
+                # step 4 - compare
+                self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
+                        msg="Data doesn't match for "+str(ftype(self.domain)))
+
+    @unittest.skipIf(mpiSize > 1, "3D Multiresolution domains don't support multiprocess yet")
     def test_readGrid3D(self):
         if self.multiplier[0] == 1:
             self.NE = [self.NX*mpiSize-1, self.NX*self.multiplier[1], self.NZ*self.multiplier[2]]
         else:
             self.NE = [self.NX*mpiSize*self.multiplier[0]-1,
                        self.NX*self.multiplier[1], self.NZ*self.multiplier[2]]
-        self.domain = Brick(self.NE[0], self.NE[1], self.NE[2], d0=mpiSize, d1=1, d2=1)
+        self.domain = Brick(n0=self.NE[0], n1=self.NE[1], n2=self.NE[2], d0=mpiSize, d1=1, d2=1)
         for ftype,fcode in self.fspaces:
             self.Ndata = [self.NX*mpiSize-1, self.NX, self.NZ]
             if ftype==ContinuousFunction:
@@ -259,34 +258,35 @@ class ReadBinaryGridTestBase(unittest.TestCase): #subclassing required
             # step 1 - generate
             ref = self.generateUniqueData(ftype)
             # step 2 & 3
-            result = self.numpy2Data2Numpy(ref, ftype, fcode)
-            # apply transformations to be able to compare
-            if self.reverse[0]:
-                result = result[...,::-1]
-            if self.reverse[1]:
-                result = result[...,::-1,:]
-            if self.reverse[2]:
-                result = result[::-1,:,:]
-            for i in range(3):
-                ref = np.repeat(ref, self.multiplier[i], axis=2-i)
-
-            # if domain larger than data: add column(s)/row(s) with fill value
-            fill=np.array(self.fill, dtype=ref.dtype)
-            realNE = adjust(self.NE,ftype)
-            for d in range(3):
-                excess = realNE[d]-ref.shape[2-d]
-                if excess > 0:
-                    shape = list(ref.shape)
-                    shape[2-d] = excess
-                    extra = fill * np.ones(shape)
-                    if self.reverse[d]:
-                        ref = np.append(extra, ref, axis=2-d)
-                    else:
-                        ref = np.append(ref, extra, axis=2-d)
-
-            # step 4 - compare
-            self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
-                    msg="Data doesn't match for "+str(ftype(self.domain)))
+            with self.assertRaises(RuntimeError):
+                result = self.numpy2Data2Numpy(ref, ftype, fcode)
+                # apply transformations to be able to compare
+                if self.reverse[0]:
+                    result = result[...,::-1]
+                if self.reverse[1]:
+                    result = result[...,::-1,:]
+                if self.reverse[2]:
+                    result = result[::-1,:,:]
+                for i in range(3):
+                    ref = np.repeat(ref, self.multiplier[i], axis=2-i)
+
+                # if domain larger than data: add column(s)/row(s) with fill value
+                fill=np.array(self.fill, dtype=ref.dtype)
+                realNE = adjust(self.NE,ftype)
+                for d in range(3):
+                    excess = realNE[d]-ref.shape[2-d]
+                    if excess > 0:
+                        shape = list(ref.shape)
+                        shape[2-d] = excess
+                        extra = fill * np.ones(shape)
+                        if self.reverse[d]:
+                            ref = np.append(extra, ref, axis=2-d)
+                        else:
+                            ref = np.append(ref, extra, axis=2-d)
+
+                # step 4 - compare
+                self.assertAlmostEquals(Lsup(ref-result), 0, delta=1e-9,
+                        msg="Data doesn't match for "+str(ftype(self.domain)))
 
 
 # The following block tests the reader for different byte orders and data
@@ -382,25 +382,27 @@ class Test_readBinaryGridZippedRipley(unittest.TestCase):
 
     def test_readCompressed2D(self):
         NE = [9, 10]
-        domain = Rectangle(NE[0], NE[1], d1=0)
+        domain = Rectangle(n0=NE[0], n1=NE[1], d1=1)
         for filename, ftype in [("RectRedF%s.grid.gz", ReducedFunction),
                 ("RectConF%s.grid.gz", ContinuousFunction)]:
             FS = ftype(domain)
             filename = os.path.join("ref_data", filename%mpiSize)
-            unzipped = self.read(filename[:-3], FS, adjust(NE, ftype))
-            zipped = self.read(filename, FS, adjust(NE, ftype), True)
-            self.assertEqual(Lsup(zipped - unzipped), 0, "Data objects don't match for "+str(FS))
+            with self.assertRaises(RuntimeError): #non-parent multidomain
+                unzipped = self.read(filename[:-3], FS, adjust(NE, ftype))
+                zipped = self.read(filename, FS, adjust(NE, ftype), True)
+                self.assertEqual(Lsup(zipped - unzipped), 0, "Data objects don't match for "+str(FS))
 
     def test_readCompressed3D(self):
         NE = [9, 9, 10]
-        domain = Brick(NE[0], NE[1], NE[2], d1=0, d2=0)
+        domain = Brick(n0=NE[0], n1=NE[1], n2=NE[2], d1=1, d2=1)
         for filename, ftype in [("BrickRedF%s.grid.gz", ReducedFunction),
                 ("BrickConF%s.grid.gz", ContinuousFunction)]:
             FS = ftype(domain)
             filename = os.path.join("ref_data", filename%mpiSize)
-            unzipped = self.read(filename[:-3], FS, adjust(NE, ftype))
-            zipped = self.read(filename, FS, adjust(NE, ftype), True)
-            self.assertEqual(Lsup(zipped - unzipped), 0, "Data objects don't match for "+str(FS))
+            with self.assertRaises(RuntimeError): #non-parent multidomain
+                unzipped = self.read(filename[:-3], FS, adjust(NE, ftype))
+                zipped = self.read(filename, FS, adjust(NE, ftype), True)
+                self.assertEqual(Lsup(zipped - unzipped), 0, "Data objects don't match for "+str(FS))
 
 
 if __name__ == '__main__':
diff --git a/ripley/test/python/run_readWriteOnRipley.py b/ripley/test/python/run_readWriteOnRipley.py
index 5edede0..7fd5902 100644
--- a/ripley/test/python/run_readWriteOnRipley.py
+++ b/ripley/test/python/run_readWriteOnRipley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/ripley/test/python/run_simplesolveOnRipley.py b/ripley/test/python/run_simplesolveOnMultiRes.py
similarity index 96%
copy from ripley/test/python/run_simplesolveOnRipley.py
copy to ripley/test/python/run_simplesolveOnMultiRes.py
index 8a2c100..99df6ff 100644
--- a/ripley/test/python/run_simplesolveOnRipley.py
+++ b/ripley/test/python/run_simplesolveOnMultiRes.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -28,7 +28,7 @@ Test suite for PDE solvers on ripley
 import esys.escriptcore.utestselect as unittest
 from esys.escriptcore.testing import *
 from esys.escript import *
-from esys.ripley import Rectangle,Brick
+from esys.ripley import MultiResolutionDomain
 from esys.escript.linearPDEs import LinearPDE, SolverOptions
 import numpy
 
@@ -57,6 +57,14 @@ for x in [(int(mpiSize**(1/3.)),int(mpiSize**(1/3.))),(2,3),(2,2),(1,2),(1,1)]:
     if NXb*NYb*NZb == mpiSize:
         break
 
+def Rectangle(**kwargs):
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
+
 class Test_SimpleSolveRipley2D_Single_Paso_BICGSTAB_Jacobi(unittest.TestCase):
      def test_solve(self):
         # Tell about how many MPI CPUs and OpenMP threads
@@ -159,6 +167,7 @@ class Test_SimpleSolveRipley2D_System_Paso_PCG_Jacobi(unittest.TestCase):
         error=Lsup(u-u_ex)
         self.assertTrue(error<REL_TOL*Lsup(u_ex), "solution error %s is too big."%error)
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_SimpleSolveRipley3D_Single_Paso_PCG_Jacobi(unittest.TestCase):
      def test_solve(self):
         domain=Brick(n0=NE0*NXb-1, n1=NE1*NYb-1, n2=NE2*NZb-1, d0=NXb, d1=NYb, d2=NZb)
@@ -187,6 +196,7 @@ class Test_SimpleSolveRipley3D_Single_Paso_PCG_Jacobi(unittest.TestCase):
         error=Lsup(u-u_ex)
         self.assertTrue(error<REL_TOL*Lsup(u_ex), "solution error %s is too big."%error)
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_SimpleSolveRipley3D_System_Paso_PCG_Jacobi(unittest.TestCase):
      def test_solve(self):
         domain=Brick(n0=NE0*NXb-1, n1=NE1*NYb-1, n2=NE2*NZb-1, d0=NXb, d1=NYb, d2=NZb)
@@ -308,6 +318,7 @@ class Test_SimpleSolveRipley2D_System_Paso_MINRES_Jacobi(unittest.TestCase):
         error=Lsup(u-u_ex)
         self.assertTrue(error<REL_TOL*Lsup(u_ex), "solution error %s is too big."%error)
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_SimpleSolveRipley3D_Single_Paso_MINRES_Jacobi(unittest.TestCase):
      def test_solve(self):
         domain=Brick(n0=NE0*NXb-1, n1=NE1*NYb-1, n2=NE2*NZb-1, d0=NXb, d1=NYb, d2=NZb)
@@ -336,6 +347,7 @@ class Test_SimpleSolveRipley3D_Single_Paso_MINRES_Jacobi(unittest.TestCase):
         error=Lsup(u-u_ex)
         self.assertTrue(error<REL_TOL*Lsup(u_ex), "solution error %s is too big."%error)
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_SimpleSolveRipley3D_System_Paso_MINRES_Jacobi(unittest.TestCase):
      def test_solve(self):
         domain=Brick(n0=NE0*NXb-1, n1=NE1*NYb-1, n2=NE2*NZb-1, d0=NXb, d1=NYb, d2=NZb)
diff --git a/ripley/test/python/run_simplesolveOnRipley.py b/ripley/test/python/run_simplesolveOnRipley.py
index 8a2c100..8a31b3c 100644
--- a/ripley/test/python/run_simplesolveOnRipley.py
+++ b/ripley/test/python/run_simplesolveOnRipley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/ripley/test/python/run_utilOnRipley.py b/ripley/test/python/run_utilOnMultiRes.py
similarity index 80%
copy from ripley/test/python/run_utilOnRipley.py
copy to ripley/test/python/run_utilOnMultiRes.py
index a63c1c2..e8411e1 100644
--- a/ripley/test/python/run_utilOnRipley.py
+++ b/ripley/test/python/run_utilOnMultiRes.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -27,7 +27,7 @@ from test_util import Test_util
 from test_util import Test_Util_SpatialFunctions, Test_Util_SpatialFunctions_noGradOnBoundary_noContact
 from test_symfuncs import Test_symfuncs
 from esys.escript import *
-from esys.ripley import Rectangle, Brick
+from esys.ripley import MultiResolutionDomain
 
 if HAVE_SYMBOLS:
     from test_symfuncs import Test_symfuncs
@@ -54,10 +54,28 @@ for x in [(int(mpiSize**(1/3.)),int(mpiSize**(1/3.))),(2,3),(2,2),(1,2),(1,1)]:
     if NXb*NYb*NZb == mpiSize:
         break
 
+def Rectangle(**kwargs):
+    kwargs['n0'] /= 2
+    kwargs['n1'] /= 2
+    m = MultiResolutionDomain(2, **kwargs)
+    return m.getLevel(1)
+
+def Brick(**kwargs):
+    kwargs['n0'] /= 2
+    kwargs['n1'] /= 2
+    kwargs['n2'] /= 2
+    m = MultiResolutionDomain(3, **kwargs)
+    return m.getLevel(1)
+
 class Test_UtilOnRipley(Test_util, Test_symfuncs, Test_util_NaN_funcs):
     def setUp(self):
         self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
         self.functionspace = FunctionOnBoundary(self.domain) # due to a bug in escript python needs to hold a reference to the domain
+        try:
+            self.workdir=os.environ['RIPLEY_WORKDIR']
+        except KeyError:
+            self.workdir='.'
+
     def tearDown(self):
         del self.functionspace
         del self.domain
@@ -70,6 +88,7 @@ class Test_Util_SpatialFunctionsOnRipley2D(Test_Util_SpatialFunctions_noGradOnBo
         del self.order
         del self.domain
 
+ at unittest.skipIf(mpiSize > 1, "3D Multiresolution domains require single process")
 class Test_Util_SpatialFunctionsOnRipley3D(Test_Util_SpatialFunctions_noGradOnBoundary_noContact):
     def setUp(self):
         self.order=1
diff --git a/ripley/test/python/run_utilOnRipley.py b/ripley/test/python/run_utilOnRipley.py
index a63c1c2..5e00af8 100644
--- a/ripley/test/python/run_utilOnRipley.py
+++ b/ripley/test/python/run_utilOnRipley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -58,6 +58,11 @@ class Test_UtilOnRipley(Test_util, Test_symfuncs, Test_util_NaN_funcs):
     def setUp(self):
         self.domain=Rectangle(n0=NE*NX-1, n1=NE*NY-1, l0=1., l1=1., d0=NX, d1=NY)
         self.functionspace = FunctionOnBoundary(self.domain) # due to a bug in escript python needs to hold a reference to the domain
+        try:
+            self.workdir=os.environ['RIPLEY_WORKDIR']
+        except KeyError:
+            self.workdir='.'
+
     def tearDown(self):
         del self.functionspace
         del self.domain
diff --git a/ripley/test/ripley_UnitTest.cpp b/ripley/test/ripley_UnitTest.cpp
index 5025613..a13a431 100644
--- a/ripley/test/ripley_UnitTest.cpp
+++ b/ripley/test/ripley_UnitTest.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2014 by University of Queensland
+* Copyright (c) 2014-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/run-escript.in b/run-escript.in
index 7cba2ae..7cbcb55 100644
--- a/run-escript.in
+++ b/run-escript.in
@@ -2,7 +2,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -22,13 +22,8 @@
 # Extra paths can be configured about a page further down
 # Search for EXTRA_PATH=""
 
-# set to 1 if this is a standalone build and ../../pkg contains the relevant
-# tools
-STANDALONE=0
-
 # set to 1 if this is part of a packaged build (.deb) and files will be
 # installed in standard locations rather than everything in a single directory
-# Do not use this together with STANDALONE
 STDLOCATION=0
 
 # Now we find the location of this script
@@ -49,6 +44,7 @@ die () {
 #Begin finding ESCRIPT_ROOT
 if [ $STDLOCATION -ne 0 ]
 then
+    #Package building scripts will replace this line
     ESCRIPT_ROOT=/usr/lib/python-escript
 else
   # We don't know the escript root so we need to work it out from the invocation
@@ -91,27 +87,12 @@ EXTRA_PYTHONPATH=$ESCRIPT_ROOT
 
 if [ $STDLOCATION -eq 1 ]
 then
-    EXTRA_LD_LIBRARY_PATH=/usr/lib/python-escript
+    EXTRA_LD_LIBRARY_PATH=$ESCRIPT_ROOT/lib
 else
     EXTRA_LD_LIBRARY_PATH=$ESCRIPT_ROOT/lib
 fi
 
-
-if [ $STANDALONE -eq 1 ]
-then
-    EXTRA_PATH=$ESCRIPT_PARENT/pkg/python/bin:$ESCRIPT_PARENT/pkg/scons/bin:$EXTRA_PATH
-    EXTRA_LD_LIBRARY_PATH=$ESCRIPT_PARENT/pkg/boost/lib:$ESCRIPT_PARENT/pkg/netcdf/lib/:$EXTRA_LD_LIBRARY_PATH
-    EXTRA_LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH
-    EXTRA_LD_LIBRARY_PATH=$ESCRIPT_PARENT/pkg/python/lib:$EXTRA_LD_LIBRARY_PATH
-    EXTRA_PYTHONPATH=$ESCRIPT_PARENT/pkg/numpy/lib/python2.6/site-packages:$ESCRIPT_PARENT/pkg/matplotlib/lib/python2.6/site-packages:$EXTRA_PYTHONPATH
-fi
-
-
 BUILDINFO_FILE="$ESCRIPT_ROOT/lib/buildvars"
-if [ "$STDLOCATION" = "1" ]
-then
-    BUILDINFO_FILE=/usr/lib/python-escript/buildvars
-fi
 if [ ! -r "$BUILDINFO_FILE" ]; then
     if [ "$1" = "-e" ]; then
         echo "export LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:\$LD_LIBRARY_PATH"
@@ -427,8 +408,8 @@ then
             # run memcheck by default
             LAST_N=$(ls -1 $LOGDIR|grep "^memcheck"|tail -1|cut -d. -f2)
             NEW_N=$(printf "%04d" $((LAST_N + 1)))
-            LOGFILE=${LOGDIR}/memcheck.${NEW_N}.xml
-            VALGRIND="valgrind --tool=memcheck --xml=yes --show-reachable=yes --error-limit=no --gen-suppressions=all --suppressions=$ESCRIPT_ROOT/scripts/escript.supp --leak-check=full --xml-file=$LOGFILE"
+            LOGFILE=${LOGDIR}/memcheck.${NEW_N}.%p.xml
+            VALGRIND="valgrind --tool=memcheck --xml=yes --show-reachable=yes --error-limit=no --suppressions=$ESCRIPT_ROOT/scripts/escript.supp --leak-check=full --xml-file=$LOGFILE"
             EXEC_CMD="$EXEC_CMD $VALGRIND"
         fi
     else
diff --git a/scons/badger_options.py b/scons/badger_options.py
index 364b9df..bef42f9 100644
--- a/scons/badger_options.py
+++ b/scons/badger_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/cgisrv3_options.py b/scons/cgisrv3_options.py
index b4bf202..2f0fe90 100644
--- a/scons/cgisrv3_options.py
+++ b/scons/cgisrv3_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/cgisrv6_options.py b/scons/cgisrv6_options.py
index 8f3d2b7..187198d 100644
--- a/scons/cgisrv6_options.py
+++ b/scons/cgisrv6_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/copper_options.py b/scons/copper_options.py
index d1d671e..d33c67a 100644
--- a/scons/copper_options.py
+++ b/scons/copper_options.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/epicuser_options.py b/scons/epicuser_options.py
index dc68e89..212e186 100644
--- a/scons/epicuser_options.py
+++ b/scons/epicuser_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/ferret_options.py b/scons/ferret_options.py
index 82b7683..ce191d1 100644
--- a/scons/ferret_options.py
+++ b/scons/ferret_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/gerbil_options.py b/scons/gerbil_options.py
index 3346c0d..12230d4 100644
--- a/scons/gerbil_options.py
+++ b/scons/gerbil_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/guineapig_intel_noomp_options.py b/scons/guineapig_intel_noomp_options.py
index 7a6c2f1..2cb85d3 100644
--- a/scons/guineapig_intel_noomp_options.py
+++ b/scons/guineapig_intel_noomp_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/guineapig_intel_options.py b/scons/guineapig_intel_options.py
index e9cc616..06ed734 100644
--- a/scons/guineapig_intel_options.py
+++ b/scons/guineapig_intel_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/guineapig_options.py b/scons/guineapig_options.py
index a69b8c6..9ee88a2 100644
--- a/scons/guineapig_options.py
+++ b/scons/guineapig_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-from templates.wheezy_options import *
+from templates.jessie_options import *
 cuda = True
 
 nvccflags = "-ccbin=g++-4.8 -arch=sm_30 -DBOOST_NOINLINE='__attribute__((noinline))'"
diff --git a/scons/guineapig_py3_options.py b/scons/guineapig_py3_options.py
index 389c045..f94f0f3 100644
--- a/scons/guineapig_py3_options.py
+++ b/scons/guineapig_py3_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/hamster_options.py b/scons/hamster_options.py
index b977a39..c6d6bce 100644
--- a/scons/hamster_options.py
+++ b/scons/hamster_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,9 +16,11 @@
 
 from templates.wheezy_options import *
 cc_optim = '-O3 -march=native'
+#cc_debug = "-g3 -O0 -DDOASSERT -DDOPROF -DBOUNDS_CHECK -D_GLIBCXX_DEBUG -fno-omit-frame-pointer -fsanitize=address --param=max-vartrack-size=90000000"
 cxx_extra = '-Wextra -Wno-unused-parameter'
 verbose = False
 mpi = 'OPENMPI'
+#ld_extra = '-fsanitize=address'
 boost_libs = ['boost_python-py27']
 parmetis = True
 umfpack = True
diff --git a/scons/templates/homebrew_10.10_options.py b/scons/magnus_options.py
similarity index 67%
copy from scons/templates/homebrew_10.10_options.py
copy to scons/magnus_options.py
index 53011ac..9155989 100644
--- a/scons/templates/homebrew_10.10_options.py
+++ b/scons/magnus_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,21 +14,6 @@
 #
 ##############################################################################
 
-# This is a template configuration file for escript/finley on Linux.
-# Copy this file to <hostname>_options.py, where <hostname> is your machine's
-# short hostname, then customize to your needs.
-
-# PREFIXES:
-# There are two ways to specify where to find dependent headers and libraries
-# (via the <dependency>_prefix):
-# 1) If your installation follows the general scheme where headers are located
-#    in <prefix>/include[32,64], and libraries in <prefix>/lib[32,64] then
-#    it is sufficient to specify this prefix, e.g. boost_prefix='/usr'
-# 2) Otherwise provide a list with two elements, where the first one is the
-#    include path, and the second the library path, e.g.
-#    boost_prefix=['/usr/include/boost1_44', '/usr/lib']
-# All <dependency>_prefix settings default to '/usr'
-
 # The options file version. SCons will refuse to build if there have been
 # changes to the set of variables and your file has not been updated.
 # This setting is mandatory.
@@ -37,20 +22,17 @@ escript_opts_version = 202
 # Installation prefix. Files will be installed in subdirectories underneath.
 # DEFAULT: '.' (current directory)
 #prefix = '/usr/local'
+#prefix = '/group/geosciences953/escript_directory/escript'
 
 # Top-level directory for intermediate build and test files.
 # DEFAULT: 'build'
 #build_dir = 'build'
 
-# C compiler command name or full path.
-# DEFAULT: auto-detected
-#cc = 'gcc'
-
 # C++ compiler command name or full path.
 # DEFAULT: auto-detected
-#cxx = 'g++'
+cxx = 'CC'
 
-# Flags to use with both C and C++ compilers. Do not set unless you know
+# Flags to use with the C++ compiler. Do not set unless you know
 # what you are doing - use cc_extra to specify additional flags!
 # DEFAULT: compiler-dependent
 #cc_flags = ''
@@ -63,72 +45,77 @@ escript_opts_version = 202
 # DEFAULT: compiler-dependent
 #cc_debug = '-g'
 
-# Additional flags to add to the C compiler only
+# Additional flags to add to the C++ compiler
 # DEFAULT: '' (empty)
-#cc_extra = ''
-
-# Additional flags to add to the C++ compiler only
-# DEFAULT: '' (empty)
-cxx_extra = '-Wno-c99-extensions'
+#cxx_extra = '-shared -fPIC -h gnu -h nomessage=47:1199:1794:1836:11709'
+cxx_extra = '-fPIC -I/group/geosciences953/escript_directory/escript/lib64/python2.6/site-packages/numpy/core/include'
 
 # Additional flags to add to the linker
 # DEFAULT: '' (empty)
-#ld_extra = ''
+#ld_extra = '-shared-intel -L/opt/cray/hdf5/1.8.11/cray/81/lib -ipo-jobs4'
+#ld_extra = '-dynamic -L/ivec/cle50/devel/PrgEnv-gnu/5.0.41/hdf5/1.8.12/lib'
+ld_extra = '-dynamic'
+
+# launcher, prelaunch, postlaunch: for MPI builds/batch system runs
+# the following substitutions are applied to all three:
+# %b = executable, %n = number of nodes, %p = number of processes,
+# %N = total number of processes, # %t = number of threads,
+# %f = name of hostfile, %h = comma-separated list of hosts,
+# %e = comma-separated list of environment variables to export
+#prelaunch = "EE=$(echo -x %e|sed -e 's/,/ -x /g')"
+prelaunch = ""
+launcher = "aprun -B %b"
+postlaunch = ""
 
 # Whether to treat compiler warnings as errors
 # DEFAULT: True
-#werror = False
+werror = False
 
 # Whether to build a debug version
 # DEFAULT: False
-#debug = True
+# debug = True
 
 # Set to True to print the full compiler/linker command line
 # DEFAULT: False
-#verbose = True
+verbose = True
 
 # Set to True to add flags that enable OpenMP parallelization
 # DEFAULT: False
-#openmp = True
+openmp = True
 
 # Additional compiler flags for OpenMP builds
 # DEFAULT: compiler-dependent
-#omp_flags = '-fopenmp'
+#omp_flags = '-homp'
+omp_flags = '-fopenmp'
 
 # Additional linker flags for OpenMP builds
 # DEFAULT: compiler-dependent
-#omp_ldflags = '-fopenmp'
+omp_ldflags = '-fopenmp'
 
 # Flavour of MPI implementation
 # Recognized values: 'none', 'MPT', 'MPICH', 'MPICH2', 'OPENMPI', 'INTELMPI'
 # DEFAULT: 'none' (disable MPI)
-#mpi = 'OPENMPI'
+mpi = 'MPICH2'
 
 # Prefix or paths to MPI headers and libraries. See note above about prefixes.
-mpi_prefix = '/usr/local'
+mpi_prefix = '/opt/cray/mpt/7.0.0/gni/mpich2-cray/83'
+
+# MPI libraries to link against. Compiler wrapper takes care of this
+#mpi_libs = ['mpich', 'mpichcxx']
+mpi_libs = []
 
-# MPI libraries to link against
-mpi_libs = ['mpi_cxx', 'mpi', 'open-rte', 'open-pal']
 
 # Prefix or paths to boost-python headers and libraries. See note above.
-boost_prefix = '/usr/local'
+#boost_prefix = '/ivec/cle50/devel/PrgEnv-intel/boost/1.55.0'
+#boost_prefix = '/ivec/cle50/devel/PrgEnv-gnu/5.0.41/boost/1.49.0'
+#boost_prefix = ['/home/caltinay/boost_1_55_0','/home/caltinay/boost_1_55_0/stage/lib']
+boost_prefix = '/group/geosciences953/escript_directory/escript'
 
 # boost-python library/libraries to link against
-#boost_libs = ['boost_python-mt']
-
-#if this is not 'python' the command will be used instead of the python
-#version scons is running on
-#pythoncmd='python'
-
-#Set to true to build with python3 [You will need to set pythoncmd as well]
-#usepython3=False
-
-#name of the python library to link against.  For Python2 you should not need
-#to set this
-#pythonlibname=''
+boost_libs = ['boost_python']
 
 # Prefix or paths to CppUnit headers and libraries. See note above.
-cppunit_prefix = '/usr/local'
+#cppunit_prefix = ''
 
 # CppUnit library/libraries to link against
 #cppunit_libs = ['cppunit']
@@ -138,7 +125,9 @@ cppunit_prefix = '/usr/local'
 netcdf = True
 
 # Prefix or paths to netCDF headers and libraries. See note above.
-netcdf_prefix = '/usr/local'
+#netcdf_prefix = '/opt/cray/netcdf-hdf5parallel/4.3.0/CRAY/81'
+#netcdf_prefix = '/ivec/cle50/devel/PrgEnv-gnu/5.0.41/netcdf/4.1.3'
+netcdf_prefix = '/group/geosciences953/escript_directory/escript'
 
 # netCDF library/libraries to link against
 netcdf_libs = ['netcdf_c++', 'netcdf']
@@ -148,7 +137,7 @@ netcdf_libs = ['netcdf_c++', 'netcdf']
 #parmetis = True
 
 # Prefix or paths to parMETIS headers and libraries. See note above.
-#parmetis_prefix = '/usr/local'
+#parmetis_prefix = '/sw/libs/parmetis/x86_64/icc-13/parmetis-4.0.2'
 
 # parMETIS library/libraries to link against
 #parmetis_libs = ['parmetis', 'metis']
@@ -172,58 +161,59 @@ netcdf_libs = ['netcdf_c++', 'netcdf']
 #mkl = True
 
 # Prefix or paths to MKL headers and libraries. See note above.
-#mkl_prefix = '/usr'
+#mkl_prefix = ['/opt/intel/composer_xe_2013.5.192/mkl/include', '/opt/intel/composer_xe_2013.5.192/mkl/lib/intel64']
 
 # MKL library/libraries to link against
-#mkl_libs = ['mkl_solver', 'mkl_em64t', 'mkl_core', 'guide', 'pthread']
+#mkl_libs = ['mkl_intel_lp64', 'mkl_intel_thread', 'mkl_core', 'pthread']
 
 # Whether to use UMFPACK (requires AMD and BLAS)
 # DEFAULT: False
 #umfpack = True
 
 # Prefix or paths to UMFPACK headers and libraries. See note above.
-#umfpack_prefix = ['/usr/include/suitesparse', '/usr/lib']
+#umfpack_prefix = '/sw/libs/umfpack/x86_64/icc-13/umfpack-5.6.1'
 
 # UMFPACK library/libraries to link against
-#umfpack_libs = ['umfpack']
+#umfpack_libs = ['umfpack', 'amd', 'suitesparseconfig']
 
 # Whether to use BoomerAMG (requires MPI)
 # DEFAULT: False
 #boomeramg = True
 
 # Prefix or paths to BoomerAMG headers and libraries. See note above.
-#boomeramg_prefix = '/usr/local'
+#boomeramg_prefix = '/sw/libs/hypre/x86_64/gcc-4.3.2/hypre-2.0.0'
 
 # BoomerAMG library/libraries to link against
 #boomeramg_libs = ['HYPRE']
+#boomeramg_libs = ['HYPRE_IJ_mv', 'HYPRE_krylov', 'HYPRE_parcsr_ls']
 
 # Flavour of LAPACK implementation
 # Recognized values: 'none', 'clapack', 'mkl'
 # DEFAULT: 'none' (do not use LAPACK)
-#lapack = 'clapack'
+#lapack = 'mkl'
 
 # Prefix or paths to LAPACK headers and libraries. See note above.
-#lapack_prefix = '/usr/local'
+#lapack_prefix = mkl_prefix
 
 # LAPACK library/libraries to link against
-#lapack_libs = ['lapack_atlas']
+#lapack_libs = ['mkl_core']
 
 # Whether to use LLNL's SILO library for Silo output file support in weipa
 # DEFAULT: False
-#silo = True
+silo = True
 
 # Prefix or paths to SILO headers and libraries. See note above.
-#silo_prefix = '/usr/local'
+silo_prefix = '/group/geosciences953/escript_directory/escript'
 
 # SILO library/libraries to link against
-#silo_libs = ['siloh5', 'hdf5']
+silo_libs = ['silo']
 
 # Whether to use LLNL's VisIt simulation interface (only version 2 supported)
 # DEFAULT: False
 #visit = True
 
 # Prefix or paths to VisIt's sim2 headers and libraries. See note above.
-#visit_prefix = '/opt/visit/2.1.0/linux-intel/libsim/V2'
+#visit_prefix = ''
 
 # Sim2 library/libraries to link against
 #visit_libs = ['simV2']
@@ -236,16 +226,6 @@ netcdf_libs = ['netcdf_c++', 'netcdf']
 ### ADVANCED OPTIONS ###
 # Do not change the following options unless you know what they do
 
-# launcher, prelaunch, postlaunch: for MPI builds/batch system runs
-# the following substitutions are applied to all three:
-# %b = executable, %n = number of nodes, %p = number of processes,
-# %N = total number of processes, # %t = number of threads,
-# %f = name of hostfile, %h = comma-separated list of hosts,
-# %e = comma-separated list of environment variables to export
-#prelaunch = "EE=$(echo %e|sed -e 's/,/ -x /g')"
-#launcher = "mpirun --gmca mpi_warn_on_fork 0 -x ${EE} --bynode --bind-to-none --host %h -np %N %b"
-#postlaunch = ""
-
 # Use intel's VSL library for random data
 # DEFAULT: False
 #vsl_random = True
@@ -254,9 +234,12 @@ netcdf_libs = ['netcdf_c++', 'netcdf']
 #sys_libs = []
 
 # Additional environmental variables to export to the tools
-#env_export = []
+# On Cray the compiler wrapper depends on a lot of environment vars
+# so we simply export everything
+import os
+env_export = os.environ.keys()
 
-#tools_names = ['default']
+#tools_names = [('intelc',{'topdir':'/opt/intel/composer_xe_2013.5.192'})]
 
 #iknowwhatimdoing = False
 
diff --git a/scons/mara_options.py b/scons/mara_options.py
index c536695..efc07a0 100644
--- a/scons/mara_options.py
+++ b/scons/mara_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/mole_clang_options.py b/scons/mole_clang_options.py
index 609f3cb..e8ac917 100644
--- a/scons/mole_clang_options.py
+++ b/scons/mole_clang_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2010 by University of Queensland
+# Copyright (c) 2003-2010 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -63,7 +63,7 @@ tools_names=['clang']
 
 # Additional flags to add to the C++ compiler
 # DEFAULT: '' (empty)
-cxx_extra = '-DBADPYTHONMACROS'
+#cxx_extra = ''
 
 # Additional flags to add to the linker
 # DEFAULT: '' (empty)
diff --git a/scons/mole_gcc_options.py b/scons/mole_gcc_options.py
deleted file mode 100644
index 17066fe..0000000
--- a/scons/mole_gcc_options.py
+++ /dev/null
@@ -1,240 +0,0 @@
-
-##############################################################################
-#
-# Copyright (c) 2003-2010 by University of Queensland
-# http://www.uq.edu.au
-#
-# Primary Business: Queensland, Australia
-# Licensed under the Open Software License version 3.0
-# http://www.opensource.org/licenses/osl-3.0.php
-#
-# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
-# Development 2012-2013 by School of Earth Sciences
-# Development from 2014 by Centre for Geoscience Computing (GeoComp)
-#
-##############################################################################
-
-# This is a template configuration file for escript/finley on Linux.
-# Copy this file to <hostname>_options.py, where <hostname> is your machine's
-# short hostname, then customize to your needs.
-
-# PREFIXES:
-# There are two ways to specify where to find dependent headers and libraries
-# (via the <dependency>_prefix):
-# 1) If your installation follows the general scheme where headers are located
-#    in <prefix>/include[32,64], and libraries in <prefix>/lib[32,64] then
-#    it is sufficient to specify this prefix, e.g. boost_prefix='/usr'
-# 2) Otherwise provide a list with two elements, where the first one is the
-#    include path, and the second the library path, e.g.
-#    boost_prefix=['/usr/include/boost1_44', '/usr/lib']
-# All <dependency>_prefix settings default to '/usr'
-
-# The options file version. SCons will refuse to build if there have been
-# changes to the set of variables and your file has not been updated.
-# This setting is mandatory.
-escript_opts_version = 202
-
-# Installation prefix. Files will be installed in subdirectories underneath.
-# DEFAULT: '.' (current directory)
-#prefix = '/usr/local'
-
-# Top-level directory for intermediate build and test files.
-# DEFAULT: 'build'
-#build_dir = 'build'
-
-# C++ compiler command name or full path.
-# DEFAULT: auto-detected
-#cxx = 'g++'
-
-# Flags to use with the C++ compiler. Do not set unless you know
-# what you are doing - use cxx_extra to specify additional flags!
-# DEFAULT: compiler-dependent
-#cc_flags = ''
-
-# Additional compiler (optimization) flags for non-debug builds
-# DEFAULT: compiler-dependent
-#cc_optim = '-O3 -mmmx -msse'
-
-# Additional compiler flags for debug builds
-# DEFAULT: compiler-dependent
-#cc_debug = '-g'
-
-# Additional flags to add to the C++ compiler only
-# DEFAULT: '' (empty)
-#cxx_extra = '-DBADPYTHONMACROS'
-
-# Additional flags to add to the linker
-# DEFAULT: '' (empty)
-#ld_extra = ''
-
-# Whether to treat compiler warnings as errors
-# DEFAULT: True
-#werror = False
-
-# Whether to build a debug version
-# DEFAULT: False
-#debug = True
-
-# Set to True to print the full compiler/linker command line
-# DEFAULT: False
-#verbose = True
-
-# Set to True to add flags that enable OpenMP parallelization
-# DEFAULT: False
-openmp = True
-
-# Additional compiler flags for OpenMP builds
-# DEFAULT: compiler-dependent
-#omp_flags = '-fopenmp'
-
-# Additional linker flags for OpenMP builds
-# DEFAULT: compiler-dependent
-#omp_ldflags = '-fopenmp'
-
-# Flavour of MPI implementation
-# Recognized values: 'none', 'MPT', 'MPICH', 'MPICH2', 'OPENMPI', 'INTELMPI'
-# DEFAULT: 'none' (disable MPI)
-#mpi = 'OPENMPI'
-
-# Prefix or paths to MPI headers and libraries. See note above about prefixes.
-#mpi_prefix = '/usr/lib/openmpi'
-
-# MPI libraries to link against
-#mpi_libs = ['mpi_cxx', 'mpi', 'open-rte', 'open-pal']
-
-# Prefix or paths to boost-python headers and libraries. See note above.
-boost_prefix = '/usr/local/boost/1.55.0'
-
-# boost-python library/libraries to link against
-boost_libs = ['boost_python']
-
-# Prefix or paths to CppUnit headers and libraries. See note above.
-cppunit_prefix = '/usr/local/cppunit/1.12.1'
-
-# CppUnit library/libraries to link against
-cppunit_libs = ['cppunit']
-
-# Whether to use the netCDF library for dump file support
-# DEFAULT: False
-netcdf = True
-
-# Prefix or paths to netCDF headers and libraries. See note above.
-netcdf_prefix = '/opt/local'
-
-# netCDF library/libraries to link against
-netcdf_libs = ['netcdf_c++', 'netcdf']
-
-# Whether to use the parMETIS library (only in conjunction with MPI)
-# DEFAULT: False
-#parmetis = True
-
-# Prefix or paths to parMETIS headers and libraries. See note above.
-#parmetis_prefix = '/usr/local'
-
-# parMETIS library/libraries to link against
-#parmetis_libs = ['parmetis', 'metis']
-
-# Whether to use the Intel PAPI (Performance API) library
-# DEFAULT: False
-#papi = True
-
-# Prefix or paths to PAPI headers and libraries. See note above.
-#papi_prefix = '/usr/local'
-
-# PAPI library/libraries to link against
-#papi_libs = ['papi']
-
-# Whether to use PAPI to instrument solver iterations
-# DEFAULT: False
-#papi_instrument_solver = True
-
-# Whether to use Intel MKL (Math Kernel Library)
-# DEFAULT: False
-#mkl = True
-
-# Prefix or paths to MKL headers and libraries. See note above.
-#mkl_prefix = '/usr'
-
-# MKL library/libraries to link against
-#mkl_libs = ['mkl_solver', 'mkl_em64t', 'mkl_core', 'guide', 'pthread']
-
-# Whether to use UMFPACK (requires AMD and BLAS)
-# DEFAULT: False
-#umfpack = True
-
-# Prefix or paths to UMFPACK headers and libraries. See note above.
-#umfpack_prefix = ['/usr/include/suitesparse', '/usr/lib']
-
-# UMFPACK library/libraries to link against
-#umfpack_libs = ['umfpack']
-
-# Whether to use BoomerAMG (requires MPI)
-# DEFAULT: False
-#boomeramg = True
-
-# Prefix or paths to BoomerAMG headers and libraries. See note above.
-#boomeramg_prefix = '/usr/local'
-
-# BoomerAMG library/libraries to link against
-#boomeramg_libs = ['HYPRE']
-
-# Flavour of LAPACK implementation
-# Recognized values: 'none', 'clapack', 'mkl'
-# DEFAULT: 'none' (do not use LAPACK)
-#lapack = 'clapack'
-
-# Prefix or paths to LAPACK headers and libraries. See note above.
-#lapack_prefix = '/usr/local'
-
-# LAPACK library/libraries to link against
-#lapack_libs = ['lapack_atlas']
-
-# Whether to use LLNL's SILO library for Silo output file support in weipa
-# DEFAULT: False
-#silo = True
-
-# Prefix or paths to SILO headers and libraries. See note above.
-#silo_prefix = '/usr/local'
-
-# SILO library/libraries to link against
-#silo_libs = ['siloh5', 'hdf5']
-
-# Whether to use LLNL's VisIt simulation interface (only version 2 supported)
-# DEFAULT: False
-#visit = True
-
-# Prefix or paths to VisIt's sim2 headers and libraries. See note above.
-#visit_prefix = '/opt/visit/2.1.0/linux-intel/libsim/V2'
-
-# Sim2 library/libraries to link against
-#visit_libs = ['simV2']
-
-# Build dynamic libraries only
-#DEFAULT: False
-#build_shared = True
-
-# work around for Python2.7 on OSX/BSD
-#DEFAULT: True
-#BADPYTHONMACROS = False
-
-### ADVANCED OPTIONS ###
-# Do not change the following options unless you know what they do
-
-# Use intel's VSL library for random data
-# DEFAULT: False
-#vsl_random = True
-
-# Extra libraries to link with
-#sys_libs = []
-
-# Additional environmental variables to export to the tools
-#env_export = []
-
-#tools_names = ['default']
-
-#iknowwhatimdoing = False
-
-#forcelazy = 'leave_alone'
-
-#forcecollres = 'leave_alone'
-
diff --git a/scons/porcupine_options.py b/scons/porcupine_options.py
index 6f5e455..d3e2b99 100644
--- a/scons/porcupine_options.py
+++ b/scons/porcupine_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/raijin_options.py b/scons/raijin_options.py
index c6565c6..69bc380 100644
--- a/scons/raijin_options.py
+++ b/scons/raijin_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/sage_options.py b/scons/sage_options.py
index 0a8829c..ad8d7bc 100644
--- a/scons/sage_options.py
+++ b/scons/sage_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -32,7 +32,7 @@
 # The options file version. SCons will refuse to build if there have been
 # changes to the set of variables and your file has not been updated.
 # This setting is mandatory.
-escript_opts_version = 201
+escript_opts_version = 202
 
 # Installation prefix. Files will be installed in subdirectories underneath.
 # DEFAULT: '.' (current directory)
diff --git a/scons/sage_py3_options.py b/scons/sage_py3_options.py
index 1b4969b..e8672ff 100644
--- a/scons/sage_py3_options.py
+++ b/scons/sage_py3_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/savanna_noomp_options.py b/scons/savanna_ice_noomp_options.py
similarity index 89%
copy from scons/savanna_noomp_options.py
copy to scons/savanna_ice_noomp_options.py
index 1b385b0..154b09f 100644
--- a/scons/savanna_noomp_options.py
+++ b/scons/savanna_ice_noomp_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -15,7 +15,7 @@
 ##############################################################################
 
 # Replace threaded mkl library by sequential one but don't touch other options
-from savanna_options import *
+from savanna_ice_options import *
 openmp = False
 mkl_libs = ['mkl_intel_lp64', 'mkl_sequential', 'mkl_core', 'pthread']
 
diff --git a/scons/badger_options.py b/scons/savanna_ice_options.py
similarity index 68%
copy from scons/badger_options.py
copy to scons/savanna_ice_options.py
index 364b9df..b6280dd 100644
--- a/scons/badger_options.py
+++ b/scons/savanna_ice_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,13 +14,11 @@
 #
 ##############################################################################
 
-from templates.wheezy_options import *
+from savanna_options import *
 
-debug = True
+build_dir = 'buildice'
 
-boost_libs = ['boost_python-py27']
-
-lapack = 'clapack'
-
-silo = True
+cxx_extra = '-ipo -sox -I/sw/pymodules/2.7/scipy-0.15.1-ice/lib/python2.7/site-packages/numpy/core/include'
 
+cuda = False
+werror = True
diff --git a/scons/savanna_noomp_options.py b/scons/savanna_noomp_options.py
index 1b385b0..2f6155d 100644
--- a/scons/savanna_noomp_options.py
+++ b/scons/savanna_noomp_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/savanna_options.py b/scons/savanna_options.py
index ced84fb..2a5a40a 100644
--- a/scons/savanna_options.py
+++ b/scons/savanna_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -53,11 +53,11 @@ escript_opts_version = 202
 
 # Additional flags to add to the C++ compiler
 # DEFAULT: '' (empty)
-cxx_extra = '-ipo -sox -I/sw/libs/numpy/x86_64/icc-14/1.8-py27_omp/lib/python2.7/site-packages/numpy/core/include'
+cxx_extra = '-ipo -sox -I/sw/pymodules/2.7/scipy-0.15.1-haswell/lib/python2.7/site-packages/numpy/core/include'
 
 # Additional flags to add to the linker
 # DEFAULT: '' (empty)
-ld_extra = '-ipo-separate -shared-intel -L/sw/libs/hdf5/1.8.12-serial/lib'
+ld_extra = '-ipo-separate -shared-intel -L/sw/libs/hdf5/1.8.14/lib'
 ld_extra += ' -wd11021 '  #silence icpc warnings about symbols ipo can't see
 
 # Whether to treat compiler warnings as errors
@@ -90,19 +90,25 @@ openmp = True
 mpi = 'INTELMPI'
 
 # Prefix or paths to MPI headers and libraries. See note above about prefixes.
-mpi_prefix = '/sw/sdev/intel/impi/5.0.1.035/intel64'
+mpi_prefix = '/sw/intel/impi/5.0.2.044/intel64'
 
 # MPI libraries to link against
 #mpi_libs = ['mpi']
 
+cuda = True
+nvccflags = "-arch=sm_35 -ccbin=icpc -DBOOST_NOINLINE='__attribute__((noinline))'"
+
+# Prefix or paths to NVidia CUDA installation. See note above. [new in 202]
+cuda_prefix = ['/sw/libs/cuda/6.5/include', '/sw/libs/cuda/6.5/lib64']
+
 # Prefix or paths to boost-python headers and libraries. See note above.
-boost_prefix = '/sw/libs/boost/1.55.0'
+boost_prefix = '/sw/libs/boost/1.57.0'
 
 # boost-python library/libraries to link against
 boost_libs = ['boost_python']
 
 # Prefix or paths to CppUnit headers and libraries. See note above.
-cppunit_prefix = '/sw/apps/cppunit/x86_64/gcc-4.3.2/cppunit-1.12.1'
+cppunit_prefix = '/sw/libs/cppunit/1.13.2'
 
 # CppUnit library/libraries to link against
 #cppunit_libs = ['cppunit']
@@ -122,10 +128,10 @@ netcdf_libs = ['netcdf_c++', 'netcdf', 'hdf5']
 parmetis = True
 
 # Prefix or paths to parMETIS headers and libraries. See note above.
-parmetis_prefix = '/sw/libs/parmetis/x86_64/icc-13/parmetis-4.0.2'
+parmetis_prefix = '/sw/libs/parmetis/4.0.3-impi'
 
 # parMETIS library/libraries to link against
-#parmetis_libs = ['parmetis', 'metis']
+parmetis_libs = ['parmetis']
 
 # Whether to use the Intel PAPI (Performance API) library
 # DEFAULT: False
@@ -146,7 +152,7 @@ parmetis_prefix = '/sw/libs/parmetis/x86_64/icc-13/parmetis-4.0.2'
 mkl = True
 
 # Prefix or paths to MKL headers and libraries. See note above.
-mkl_prefix = ['/sw/sdev/intel/composer_xe_2015/mkl/include', '/sw/sdev/intel/composer_xe_2015/mkl/lib/intel64']
+mkl_prefix = ['/sw/intel/composer_xe_2015.1.133/mkl/include', '/sw/intel/composer_xe_2015.1.133/mkl/lib/intel64']
 
 # MKL library/libraries to link against
 mkl_libs = ['mkl_intel_lp64', 'mkl_intel_thread', 'mkl_core', 'pthread']
@@ -166,7 +172,7 @@ mkl_libs = ['mkl_intel_lp64', 'mkl_intel_thread', 'mkl_core', 'pthread']
 #boomeramg = True
 
 # Prefix or paths to BoomerAMG headers and libraries. See note above.
-boomeramg_prefix = '/sw/libs/hypre/x86_64/gcc-4.3.2/hypre-2.0.0'
+boomeramg_prefix = '/sw/libs/hypre/2.0.0'
 
 # BoomerAMG library/libraries to link against
 boomeramg_libs = ['HYPRE']
@@ -188,7 +194,7 @@ lapack_libs = ['mkl_core']
 silo = True
 
 # Prefix or paths to SILO headers and libraries. See note above.
-silo_prefix = '/sw/libs/silo/4.9.1'
+silo_prefix = '/sw/libs/silo/4.10.2'
 
 # SILO library/libraries to link against
 silo_libs = ['siloh5', 'hdf5']
@@ -212,7 +218,7 @@ build_shared = True
 # Do not change the following options unless you know what they do
 
 prelaunch = ""
-launcher = "srun --tasks=%N --ntasks-per-node=%p --cpus-per-task=%t %b"
+launcher = "srun --nodes=%n --ntasks=%N --ntasks-per-node=%p --cpus-per-task=%t --cpu_bind=quiet %b"
 postlaunch = ""
 
 # Use intel's VSL library for random data
@@ -225,7 +231,7 @@ postlaunch = ""
 # Additional environmental variables to export to the tools
 env_export = ['INTEL_LICENSE_FILE']
 
-tools_names = [('intelc',{'topdir':'/sw/sdev/intel/composer_xe_2015'})]
+tools_names = [('intelc',{'topdir':'/sw/intel/composer_xe_2015.1.133'})]
 
 
 #iknowwhatimdoing = False
@@ -234,3 +240,8 @@ tools_names = [('intelc',{'topdir':'/sw/sdev/intel/composer_xe_2015'})]
 
 #forcecollres = 'leave_alone'
 
+# uncomment the following four options to build with mpt (check modules!)
+#build_dir = 'buildmpt'
+#mpi = 'MPT'
+#mpi_prefix = '/opt/sgi/mpt/mpt-2.10'
+#parmetis_prefix = '/sw/libs/parmetis/4.0.3-mpt'
diff --git a/scons/squirrel_options.py b/scons/squirrel_options.py
index 4373c5f..5365d90 100644
--- a/scons/squirrel_options.py
+++ b/scons/squirrel_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2013 by University of Queensland
+# Copyright (c) 2003-2013 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/standalone_options.py b/scons/standalone_options.py
index a00398d..518b989 100644
--- a/scons/standalone_options.py
+++ b/scons/standalone_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/centos7_0_options.py b/scons/templates/centos7_0_options.py
index 2cf2ff6..933eaf3 100644
--- a/scons/templates/centos7_0_options.py
+++ b/scons/templates/centos7_0_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/fedora21_5_options.py b/scons/templates/fedora21_5_options.py
index 07149c3..3ecf23d 100644
--- a/scons/templates/fedora21_5_options.py
+++ b/scons/templates/fedora21_5_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/freebsd10_0_options.py b/scons/templates/freebsd10_0_options.py
index f2692de..e3139db 100644
--- a/scons/templates/freebsd10_0_options.py
+++ b/scons/templates/freebsd10_0_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/homebrew_10.10_options.py b/scons/templates/homebrew_10.10_options.py
index 53011ac..8555c6b 100644
--- a/scons/templates/homebrew_10.10_options.py
+++ b/scons/templates/homebrew_10.10_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/homebrew_options.py b/scons/templates/homebrew_options.py
index b75305d..8a18b50 100644
--- a/scons/templates/homebrew_options.py
+++ b/scons/templates/homebrew_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/jessie_mpi_options.py b/scons/templates/jessie_mpi_options.py
index e174078..5441430 100644
--- a/scons/templates/jessie_mpi_options.py
+++ b/scons/templates/jessie_mpi_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/jessie_options.py b/scons/templates/jessie_options.py
index 71744b3..4c99ec8 100644
--- a/scons/templates/jessie_options.py
+++ b/scons/templates/jessie_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -306,17 +306,3 @@ build_shared = True
 # DEFAULT: False
 #papi_instrument_solver = True
 
-from site_init import getdebbuildflags
-# Now we add the debian build flags
-debstuff=getdebbuildflags()
-if (len(debstuff)>0):
-  print("Building with the following additional flags from debian: "+str(debstuff))
-
-for i in debstuff:
-  k=i[0]
-  v=i[1]
-  print("Processing: "+k+" || "+v)
-  try:
-    exec(k+"+=' "+v+"'")
-  except NameError:   
-    exec(k+"='"+v+"'")
diff --git a/scons/templates/jessie_py3_mpi_options.py b/scons/templates/jessie_py3_mpi_options.py
index 407e8d2..ff41de8 100644
--- a/scons/templates/jessie_py3_mpi_options.py
+++ b/scons/templates/jessie_py3_mpi_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/jessie_py3_options.py b/scons/templates/jessie_py3_options.py
index dabb502..03f0b16 100644
--- a/scons/templates/jessie_py3_options.py
+++ b/scons/templates/jessie_py3_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/macports_10.10_options.py b/scons/templates/macports_10.10_options.py
index 5cdfdbd..c1d452e 100644
--- a/scons/templates/macports_10.10_options.py
+++ b/scons/templates/macports_10.10_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/macports_options.py b/scons/templates/macports_options.py
index 8b369b0..6a01cd0 100644
--- a/scons/templates/macports_options.py
+++ b/scons/templates/macports_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/opensuse13_2_options.py b/scons/templates/opensuse13_2_options.py
index f9b0874..9b425bf 100644
--- a/scons/templates/opensuse13_2_options.py
+++ b/scons/templates/opensuse13_2_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/trusty_options.py b/scons/templates/trusty_options.py
index aad8c8f..5507550 100644
--- a/scons/templates/trusty_options.py
+++ b/scons/templates/trusty_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/utopic_options.py b/scons/templates/utopic_options.py
index aad8c8f..5507550 100644
--- a/scons/templates/utopic_options.py
+++ b/scons/templates/utopic_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/wheezy_mpi_options.py b/scons/templates/wheezy_mpi_options.py
index 4f82f2e..a94dfe1 100644
--- a/scons/templates/wheezy_mpi_options.py
+++ b/scons/templates/wheezy_mpi_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/wheezy_options.py b/scons/templates/wheezy_options.py
index c4c839f..216dfc4 100644
--- a/scons/templates/wheezy_options.py
+++ b/scons/templates/wheezy_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/wheezy_py3_mpi_options.py b/scons/templates/wheezy_py3_mpi_options.py
index 8cc5f43..fcc46e3 100644
--- a/scons/templates/wheezy_py3_mpi_options.py
+++ b/scons/templates/wheezy_py3_mpi_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/wheezy_py3_options.py b/scons/templates/wheezy_py3_options.py
index 2961c6a..efcc715 100644
--- a/scons/templates/wheezy_py3_options.py
+++ b/scons/templates/wheezy_py3_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2015 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/windows_intelc_options.py b/scons/templates/windows_intelc_options.py
index fd6c126..9215f21 100644
--- a/scons/templates/windows_intelc_options.py
+++ b/scons/templates/windows_intelc_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/windows_msvc90_options.py b/scons/templates/windows_msvc90_options.py
index a4c77da..545bf7f 100644
--- a/scons/templates/windows_msvc90_options.py
+++ b/scons/templates/windows_msvc90_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/templates/windows_options.py b/scons/templates/windows_options.py
index 5d8034b..892b410 100644
--- a/scons/templates/windows_options.py
+++ b/scons/templates/windows_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/vayu_options.py b/scons/vayu_options.py
index eba498b..4dbc4ff 100644
--- a/scons/vayu_options.py
+++ b/scons/vayu_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/vm_options.py b/scons/vm_options.py
index 2661645..3130e2d 100644
--- a/scons/vm_options.py
+++ b/scons/vm_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scons/vmw_options.py b/scons/vmw_options.py
index b52efbd..a02cf63 100644
--- a/scons/vmw_options.py
+++ b/scons/vmw_options.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/scripts/extracttests.sh b/scripts/extracttests.sh
index b502ccc..8212fc8 100755
--- a/scripts/extracttests.sh
+++ b/scripts/extracttests.sh
@@ -1,42 +1,58 @@
+#!/bin/bash
 
-DEST=../testfiles
-mkdir $DEST
-if [ $? != 0 ]
+
+# To be run from an esys13 root directory which has had a full build done in it.
+#This will make a directory of files which can be shipped elsewhere to test an install
+
+
+if [ $# -lt 1 ]
 then
- echo "$DEST directory exists. Exiting"
- exit 1
+   echo "Usage: $0 targetdirectory"
+   exit 1
 fi
 
-cp -r * $DEST
-cd $DEST
+if [ -f $1 ]
+then
+   echo "Target exists and is not a directory"
+   exit 2
+fi
 
-rm -rf bin
-rm -rf debian/
-rm -rf lib
-rm -rf packaging
-rm -f config.log CREDITS.txt log README_LICENSE SConstruct svn_version utest.sh
-find . -name '.s*' | xargs rm -rf
-find . -name 'src' | xargs rm -rf
-find . -name 'py_src' | xargs rm -rf
-find . -name 'SConscript' | xargs rm -rf
-find . -name '*.c' | xargs rm -rf
-find . -name '*.h' | xargs rm -rf
-find . -name '*.cpp' | xargs rm -rf
-rm -rf tools site_scons scons scripts
-rm -rf release
-find build -type f | xargs rm
-rm -rf esys
-find . -name '__pycache__' | xargs rm -rf
-find . -name '*.tex' | xargs rm -rf
-cd doc
-rm -rf epydoc cookbook doxygen install inversion manpage user *.sh *.cls
-cd ..
-find . -name '*.pyc' | xargs rm -f
+if [ "$1" == ".." ]
+then
+   # coz if you call this from inside a directory called src, you
+   # wipe out your working copy
+   echo "Using .. as a target is a bad idea. Suggest ../tests"
+   exit 2
+fi
 
-cd ..
-tar -czf testfiles.tar.gz testfiles
-rm -rf testfiles
+if [ ! -f itest.sh ]
+then
+   echo "itest.sh not found. Have you run a build?"
+   exit 3
+fi
 
+if [ ! -d $1 ]
+then
+   mkdir $1
+fi
 
+targetdir=$1
 
+cp -r * $targetdir
+cd $targetdir || exit 4
 
+rm -rf esys
+rm -rf bin
+rm -rf lib
+rm -rf utest.sh
+rm -rf 
+find build -name '*.o' | xargs rm
+find build -name '*.os' | xargs rm
+find build -name '*.so' | xargs rm
+find build -name '*.a' | xargs rm
+find build -name '*.pyc' | xargs rm
+find . -name 'src' | xargs rm -r
+rm -r scons
+rm -r doc/user doc/cookbook 
+find doc -name '*.tex' | xargs rm
+rm -rf debian
diff --git a/site_scons/dependencies.py b/site_scons/dependencies.py
index 82269ab..fb95561 100644
--- a/site_scons/dependencies.py
+++ b/site_scons/dependencies.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -223,6 +223,17 @@ def checkNumpy(env):
 
     return conf.Finish()
 
+def checkCUDA(env):
+    try:
+        cuda_inc_path,cuda_lib_path=findLibWithHeader(env, 'cudart', 'thrust/version.h', env['cuda_prefix'], lang='c++')
+        env.AppendUnique(CPPPATH = [cuda_inc_path])
+        env.AppendUnique(LIBPATH = [cuda_lib_path])
+        env.PrependENVPath(env['LD_LIBRARY_PATH_KEY'], cuda_lib_path)
+        env['cuda']=True
+    except:
+        env['cuda']=False
+    return env
+
 def checkCppUnit(env):
     try:
         cppunit_inc_path,cppunit_lib_path=findLibWithHeader(env, env['cppunit_libs'], 'cppunit/TestFixture.h', env['cppunit_prefix'], lang='c++')
diff --git a/site_scons/extractdebbuild.py b/site_scons/extractdebbuild.py
index edc0645..45f5141 100644
--- a/site_scons/extractdebbuild.py
+++ b/site_scons/extractdebbuild.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2015 by University of Queensland
+# Copyright (c) 2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2015 by University of Queensland
+__copyright__="""Copyright (c) 2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/site_scons/grouptest.py b/site_scons/grouptest.py
index bdc31c0..5530f87 100644
--- a/site_scons/grouptest.py
+++ b/site_scons/grouptest.py
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -69,8 +69,13 @@ class GroupTest(object):
                 res=res+"export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DYLD_LIBRARY_PATH\n"
         if stdloc:
             res=res+"\nexport OLD_PYTHON=$PYTHONPATH\nBINRUNNER=\"run-escript -b $2\"\nPYTHONRUNNER=\"run-escript $2\"\nBATCH_ROOT=`pwd`\n"
+            res=res+"PYTHONTESTRUNNER=\"run-escript $2 $BATCH_ROOT/tools/testrunner.py\"\n"
         else:
-            res=res+"\nexport OLD_PYTHON=%s:$PYTHONPATH\nBINRUNNER=\"%s/bin/run-escript -b $2\"\nPYTHONRUNNER=\"%s/bin/run-escript $2\"\nBATCH_ROOT=`pwd`\n"%(prefix,prefix,prefix)
+            res=res+"""\nexport OLD_PYTHON={0}:$PYTHONPATH
+BINRUNNER=\"{0}/bin/run-escript -b $2\"
+PYTHONRUNNER=\"{0}/bin/run-escript $2\"
+PYTHONTESTRUNNER=\"{0}/bin/run-escript $2 {0}/tools/testrunner.py\"
+BATCH_ROOT=`pwd`\n""".format(prefix)
         res=res+"BUILD_DIR=$1"+"/"+build_platform
         res=res+"\nif [ ! -d $BUILD_DIR ]\nthen\n echo Can not find build directory $BUILD_DIR\n exit 2\nfi\n" 
         #res=res+"if [ $# -lt 2 ]\nthen\n echo Usage: $0 bin_run_cmd python_run_cmd\n exit 2\nfi\n"
@@ -79,6 +84,7 @@ class GroupTest(object):
 
     def makeString(self):
         res=""
+        build_dir = self.working_dir.replace("$BATCH_ROOT", "$BUILD_DIR")
         if self.single_processor_only:
             res+="#if [ $MPIPROD -le 1 ]; then\n"
             res+='if [ "$MPITYPE" == "mpi=none" ]; then\n'
@@ -86,19 +92,32 @@ class GroupTest(object):
         else:
             tt=""
         for d in self.mkdirs:
-            res=res+tt+"if [ ! -d "+str(d)+" ]\n"+tt+"then\n"+tt+"\tmkdir "+d+"\n"+tt+"fi\n"
+            res=res+tt+"if [ ! -d "+str(d)+" ]\n"+tt+"then\n"+tt+"\tmkdir -p "+str(d)+"\n"+tt+"fi\n"
         for v in self.evars:
             res=res+tt+"export "+str(v[0])+"="+str(v[1])+"\n"
+        res=res+tt+"if [ ! -d "+str(self.working_dir)+" ]\n"+tt+"then\n"+tt+"\tmkdir -p "+str(self.working_dir)+"\n"+tt+"fi\n"
         if len(self.python_dir)>0:
             res=res+tt+"export PYTHONPATH="+self.python_dir+":$OLD_PYTHON"+"\n"+tt+"cd "+self.working_dir+"\n"
         else:
             res=res+tt+"export PYTHONPATH=$OLD_PYTHON"+"\n"+tt+"cd "+self.working_dir+"\n"
         for t in self.test_list:
             res=res+tt+"echo Starting "+t+"\ndate\n"
-            res=res+tt+self.exec_cmd+' '+t+' || failed '+t+'\n'
-            res=res+tt+"echo Completed "+t+"\n"
+            skipoutputfile = ""
+            failoutputfile = ""
+            cmd = self.exec_cmd
+            exit_on_failure = " || failed %s"%t
+            if "examples" not in build_dir and "PYTHONRUNNER" in self.exec_cmd \
+                    and "/tools/" not in build_dir:
+                skipoutputfile = " -skipfile={0}/{1}".format(build_dir, t.replace(".py", ".skipped"))
+                failoutputfile = " -failfile={0}/{1}".format(build_dir, t.replace(".py", ".failed"))
+                cmd = cmd.replace("PYTHONRUNNER", "PYTHONTESTRUNNER")
+                exit_on_failure = ""
+            res += "".join([tt, cmd, t, failoutputfile, skipoutputfile, exit_on_failure, "\n"])
+            res += tt+"echo Completed "+t+"\n"
         if self.single_processor_only:
             res+="fi\n"
         res=res+"\n"
         return res
-        
+    
+    def makeFooter(self):
+        return "find $BUILD_DIR -name '*.failed' | xargs cat; find $BUILD_DIR -name '*.failed' | xargs cat | diff -q - /dev/null >/dev/null\n"
diff --git a/site_scons/site_init.py b/site_scons/site_init.py
index 8a391b1..c6457be 100644
--- a/site_scons/site_init.py
+++ b/site_scons/site_init.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -121,6 +121,7 @@ def generateTestScripts(env, TestGroups):
         utest.write(GroupTest.makeHeader(env['PLATFORM'], env['prefix'], False))
         for tests in TestGroups:
             utest.write(tests.makeString())
+        utest.write(tests.makeFooter())
         utest.close()
         env.Execute(Chmod('utest.sh', 0o755))
         print("Generated utest.sh.")
@@ -131,6 +132,7 @@ def generateTestScripts(env, TestGroups):
         for tests in TestGroups:
           if tests.exec_cmd=='$PYTHONRUNNER ':
             utest.write(tests.makeString())
+            utest.write(tests.makeFooter())
         utest.close()
         env.Execute(Chmod('itest.sh', 0o755))
         print("Generated itest.sh.")        
@@ -191,12 +193,13 @@ def runPyUnitTest(target, source, env):
            app = "cd "+ pn +" & "+sys.executable + " " + sn
    else:
      skipfile = os.path.join(env['BUILD_DIR'], sn[:-3]) + ".skipped"
+     failfile = os.path.join(env['BUILD_DIR'], sn[:-3]) + ".failed"
      try:
          os.unlink(skipfile)
      except Exception as e:
         pass
      app = "cd "+pn+"; "+binpath(env, "run-escript")+" -ov "+binpath(env,
-            "../tools/testrunner.py")+" -outputfile="+skipfile+" "+sn
+            "../tools/testrunner.py")+" -skipfile="+skipfile+" "+"-failfile="+failfile+" "+"-exit "+sn
    print "Executing test: ",app
    if env.Execute(app) == 0:
       open(str(target[0]),'w').write("PASSED\n")
diff --git a/speckley/py_src/SConscript b/speckley/py_src/SConscript
index 9eeb7c2..48b5b71 100644
--- a/speckley/py_src/SConscript
+++ b/speckley/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/speckley/py_src/__init__.py b/speckley/py_src/__init__.py
index 8b72762..a45c368 100644
--- a/speckley/py_src/__init__.py
+++ b/speckley/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@
 """A domain meshed with uniform rectangles or quadrilaterals
 """
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/speckley/src/AbstractAssembler.cpp b/speckley/src/AbstractAssembler.cpp
index a565f93..8f5ff8b 100644
--- a/speckley/src/AbstractAssembler.cpp
+++ b/speckley/src/AbstractAssembler.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -12,6 +12,11 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/AbstractAssembler.h>
 
 namespace speckley {
diff --git a/speckley/src/AbstractAssembler.h b/speckley/src/AbstractAssembler.h
index 74ed304..95deaad 100644
--- a/speckley/src/AbstractAssembler.h
+++ b/speckley/src/AbstractAssembler.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/Brick.cpp b/speckley/src/Brick.cpp
index 0712e51..a3ccaf0 100644
--- a/speckley/src/Brick.cpp
+++ b/speckley/src/Brick.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,8 +14,13 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+#include <boost/math/special_functions/fpclassify.hpp> // for isnan
+
 #include <speckley/Brick.h>
 #include <speckley/DefaultAssembler3D.h>
+#include <speckley/WaveAssembler3D.h>
 #include <esysUtils/esysFileWriter.h>
 #include <esysUtils/EsysRandom.h>
 #include <esysUtils/index.h>
@@ -41,8 +46,12 @@
 #include <iomanip>
 #include <limits>
 
-using namespace std;
+namespace bm=boost::math;
 using esysUtils::FileWriter;
+using std::max;
+using std::min;
+using std::vector;
+using std::string;
 
 namespace speckley {
 
@@ -206,7 +215,7 @@ Brick::~Brick()
 #endif
 }
 
-string Brick::getDescription() const
+std::string Brick::getDescription() const
 {
     return "speckley::Brick";
 }
@@ -225,7 +234,7 @@ bool Brick::operator==(const AbstractDomain& other) const
     return false;
 }
 
-void Brick::readNcGrid(escript::Data& out, string filename, string varname,
+void Brick::readNcGrid(escript::Data& out, std::string filename, std::string varname,
             const ReaderParameters& params) const
 {
 #ifdef USE_NETCDF
@@ -348,7 +357,7 @@ void Brick::readNcGrid(escript::Data& out, string filename, string varname,
                 const dim_t srcIndex=(z0+z_mult*z)*num1*num0
                                   +(y0+y_mult*y)*num0
                                   +(x0+x_mult*x);
-                if (!isnan(values[srcIndex])) {
+                if (!bm::isnan(values[srcIndex])) {
                     for (index_t m2=0; m2<params.multiplier[2]; m2++) {
                         for (index_t m1=0; m1<params.multiplier[1]; m1++) {
                             for (index_t m0=0; m0<params.multiplier[0]; m0++) {
@@ -372,7 +381,7 @@ void Brick::readNcGrid(escript::Data& out, string filename, string varname,
 }
 
 #ifdef USE_BOOSTIO
-void Brick::readBinaryGridFromZipped(escript::Data& out, string filename,
+void Brick::readBinaryGridFromZipped(escript::Data& out, std::string filename,
                            const ReaderParameters& params) const
 {
     // the mapping is not universally correct but should work on our
@@ -393,7 +402,7 @@ void Brick::readBinaryGridFromZipped(escript::Data& out, string filename,
 }
 #endif
 
-void Brick::readBinaryGrid(escript::Data& out, string filename,
+void Brick::readBinaryGrid(escript::Data& out, std::string filename,
                            const ReaderParameters& params) const
 {
     // the mapping is not universally correct but should work on our
@@ -414,7 +423,7 @@ void Brick::readBinaryGrid(escript::Data& out, string filename,
 }
 
 template<typename ValueType>
-void Brick::readBinaryGridImpl(escript::Data& out, const string& filename,
+void Brick::readBinaryGridImpl(escript::Data& out, const std::string& filename,
                                const ReaderParameters& params) const
 {
     // check destination function space
@@ -445,11 +454,11 @@ void Brick::readBinaryGridImpl(escript::Data& out, const string& filename,
         throw SpeckleyException("readBinaryGrid(): reversing only supported in Z-direction currently");
 
     // check file existence and size
-    ifstream f(filename.c_str(), ifstream::binary);
+    std::ifstream f(filename.c_str(), std::ifstream::binary);
     if (f.fail()) {
         throw SpeckleyException("readBinaryGrid(): cannot open file");
     }
-    f.seekg(0, ios::end);
+    f.seekg(0, std::ios::end);
     const int numComp = out.getDataPointSize();
     const dim_t filesize = f.tellg();
     const dim_t reqsize = params.numValues[0]*params.numValues[1]*params.numValues[2]*numComp*sizeof(ValueType);
@@ -552,7 +561,7 @@ void Brick::readBinaryGridImpl(escript::Data& out, const string& filename,
                                         byte_swap32(cval);
                                     }
                                 }
-                                if (!isnan(val)) {
+                                if (!bm::isnan(val)) {
                                     for (int q=0; q<dpp; q++) {
                                         *dest++ = static_cast<double>(val);
                                     }
@@ -601,14 +610,14 @@ void Brick::readBinaryGridZippedImpl(escript::Data& out, const string& filename,
             throw SpeckleyException("readBinaryGridFromZipped(): all multipliers must be positive");
 
     // check file existence and size
-    ifstream f(filename.c_str(), ifstream::binary);
+    std::ifstream f(filename.c_str(), std::ifstream::binary);
     if (f.fail()) {
         throw SpeckleyException("readBinaryGridFromZipped(): cannot open file");
     }
-    f.seekg(0, ios::end);
+    f.seekg(0, std::ios::end);
     const int numComp = out.getDataPointSize();
     dim_t filesize = f.tellg();
-    f.seekg(0, ios::beg);
+    f.seekg(0, std::ios::beg);
     std::vector<char> compressed(filesize);
     f.read((char*)&compressed[0], filesize);
     f.close();
@@ -711,7 +720,7 @@ void Brick::readBinaryGridZippedImpl(escript::Data& out, const string& filename,
                                         byte_swap32(cval);
                                     }
                                 }
-                                if (!isnan(val)) {
+                                if (!bm::isnan(val)) {
                                     for (int q=0; q<dpp; q++) {
                                         *dest++ = static_cast<double>(val);
                                     }
@@ -788,7 +797,7 @@ void Brick::interpolateFromCorners(escript::Data &out) const
     }
 }
 
-void Brick::writeBinaryGrid(const escript::Data& in, string filename,
+void Brick::writeBinaryGrid(const escript::Data& in, std::string filename,
                             int byteOrder, int dataType) const
 {
     // the mapping is not universally correct but should work on our
@@ -848,7 +857,7 @@ void Brick::writeBinaryGridImpl(const escript::Data& in,
         for (index_t y=0; y<myN1; y++) {
             const dim_t fileofs = (m_offset[0]+(m_offset[1]+y)*totalN0
                                 +(m_offset[2]+z)*totalN0*totalN1)*sizeof(ValueType);
-            ostringstream oss;
+            std::ostringstream oss;
 
             for (index_t x=0; x<myN0; x++) {
                 const double* sample = in.getSampleDataRO(
@@ -980,8 +989,8 @@ void Brick::dump(const string& fileName) const
         vector<string> tempstrings;
         vector<char*> names;
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/mesh";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/mesh";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -992,8 +1001,8 @@ void Brick::dump(const string& fileName) const
         tempstrings.clear();
         names.clear();
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/nodeId";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/nodeId";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -1003,8 +1012,8 @@ void Brick::dump(const string& fileName) const
         tempstrings.clear();
         names.clear();
         for (dim_t i=0; i<m_mpiInfo->size; i++) {
-            stringstream path;
-            path << "/block" << setw(4) << setfill('0') << right << i << "/elementId";
+            std::stringstream path;
+            path << "/block" << std::setw(4) << std::setfill('0') << std::right << i << "/elementId";
             tempstrings.push_back(path.str());
             names.push_back((char*)tempstrings.back().c_str());
         }
@@ -1033,6 +1042,7 @@ const dim_t* Brick::borrowSampleReferenceIDs(int fsType) const
         case Nodes:
             return &m_nodeId[0];
         case Elements:
+        case ReducedElements:
             return &m_elementId[0];
         case Points:
             return &m_diracPointNodeIDs[0];
@@ -1059,13 +1069,39 @@ void Brick::setToSize(escript::Data& out) const
 {
     if (out.getFunctionSpace().getTypeCode() == Elements) {
         out.requireWrite();
-        const dim_t numQuad = out.getNumDataPointsPerSample();
-        const double size=sqrt(m_dx[0]*m_dx[0]+m_dx[1]*m_dx[1]+m_dx[2]*m_dx[2]);
+        const dim_t numQuad = m_order + 1;
         const dim_t numElements = getNumElements();
+        const double *quad_locs = point_locations[m_order-2];
+        //since elements are uniform, calc the first and copy to others
+        double* first_element = out.getSampleDataRW(0);
+#pragma omp parallel for
+        for (short qz = 0; qz < m_order; qz++) {
+            const double z = quad_locs[qz+1] - quad_locs[qz];
+            for (short qy = 0; qy < m_order; qy++) {
+                const double y = quad_locs[qy+1] - quad_locs[qy];
+                for (short qx = 0; qx < m_order; qx++) {
+                    const double x = quad_locs[qx+1] - quad_locs[qx];
+                    first_element[INDEX3(qx,qy,qz,numQuad,numQuad)]= sqrt(x*x + y*y + z*z);
+                }
+                first_element[INDEX3(m_order,qy,qz,numQuad,numQuad)] 
+                        = first_element[INDEX3(0,qy,qz,numQuad,numQuad)];
+            }
+            for (short qx = 0; qx < numQuad; qx++) {
+                first_element[INDEX3(qx,m_order,qz,numQuad,numQuad)] 
+                        = first_element[INDEX3(qx,0,qz,numQuad,numQuad)];
+            }
+        }
+        for (short qy = 0; qy < numQuad; qy++) {
+            for (short qx = 0; qx < numQuad; qx++) {
+                first_element[INDEX3(qx,qy,m_order,numQuad,numQuad)] 
+                        = first_element[INDEX3(qx,qy,0,numQuad,numQuad)];
+            }
+        }
+        const size_t size = numQuad*numQuad*numQuad*sizeof(double);
 #pragma omp parallel for
         for (index_t k = 0; k < numElements; ++k) {
             double* o = out.getSampleDataRW(k);
-            std::fill(o, o+numQuad, size);
+            memcpy(o, first_element, size);
         }
     } else {
         std::stringstream msg;
@@ -1095,11 +1131,10 @@ void Brick::Print_Mesh_Info(const bool full) const
 //protected
 void Brick::assembleCoordinates(escript::Data& arg) const
 {
-    escriptDataC dc = arg.getDataC();
     int numDim = m_numDim;
-    if (!isDataPointShapeEqual(&dc, 1, &numDim))
+    if (&arg!=0 && !arg.isDataPointShapeEqual(1, &numDim))
         throw SpeckleyException("setToX: Invalid Data object shape");
-    if (!numSamplesEqual(&dc, 1, getNumNodes()))
+    if (&arg!=0 && !arg.numSamplesEqual(1, getNumNodes()))
         throw SpeckleyException("setToX: Illegal number of samples in Data object");
 
     const dim_t NN0 = m_NN[0];
@@ -1365,23 +1400,48 @@ void Brick::interpolateElementsOnNodes(escript::Data& out,
     const dim_t max_x = m_NN[0];
     const dim_t max_y = m_NN[1];
     const dim_t max_z = m_NN[2];
+    const int inFS = in.getFunctionSpace().getTypeCode();
     out.requireWrite();
     //init to zero so we can do some sums without undefined, may not be required
     memset(out.getSampleDataRW(0), 0, sizeof(double)*quads*quads*numComp);
     // the summation portion
-    for (dim_t colouring = 0; colouring < 2; colouring++) {
-#pragma omp parallel for
-        for (dim_t ez = colouring; ez < NE2; ez += 2) {
-            for (dim_t ey = 0; ey < NE1; ey++) {
-                for (dim_t ex = 0; ex < NE0; ex++) {
-                    dim_t start = m_order * (INDEX3(ex, ey, ez, max_x, max_y));
-                    const double *e_in = in.getSampleDataRO(INDEX3(ex,ey,ez,NE0,NE1));
-                    for (int qz = 0; qz < quads; qz++) {
-                        for (int qy = 0; qy < quads; qy++) {
-                            for (int qx = 0; qx < quads; qx++) {
-                                double *n_out = out.getSampleDataRW(start + INDEX3(qx, qy, qz, max_x, max_y));
-                                for (dim_t comp = 0; comp < numComp; comp++) {
-                                    n_out[comp] += e_in[INDEX4(comp, qx, qy, qz, numComp, quads, quads)];
+    if (inFS == ReducedElements) {
+        for (dim_t colouring = 0; colouring < 2; colouring++) {
+    #pragma omp parallel for
+            for (dim_t ez = colouring; ez < NE2; ez += 2) {
+                for (dim_t ey = 0; ey < NE1; ey++) {
+                    for (dim_t ex = 0; ex < NE0; ex++) {
+                        dim_t start = m_order * (INDEX3(ex, ey, ez, max_x, max_y));
+                        const double *e_in = in.getSampleDataRO(INDEX3(ex,ey,ez,NE0,NE1));
+                        for (int qz = 0; qz < quads; qz++) {
+                            for (int qy = 0; qy < quads; qy++) {
+                                for (int qx = 0; qx < quads; qx++) {
+                                    double *n_out = out.getSampleDataRW(start + INDEX3(qx, qy, qz, max_x, max_y));
+                                    for (dim_t comp = 0; comp < numComp; comp++) {
+                                        n_out[comp] += e_in[comp];
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }        
+    } else {
+        for (dim_t colouring = 0; colouring < 2; colouring++) {
+    #pragma omp parallel for
+            for (dim_t ez = colouring; ez < NE2; ez += 2) {
+                for (dim_t ey = 0; ey < NE1; ey++) {
+                    for (dim_t ex = 0; ex < NE0; ex++) {
+                        dim_t start = m_order * (INDEX3(ex, ey, ez, max_x, max_y));
+                        const double *e_in = in.getSampleDataRO(INDEX3(ex,ey,ez,NE0,NE1));
+                        for (int qz = 0; qz < quads; qz++) {
+                            for (int qy = 0; qy < quads; qy++) {
+                                for (int qx = 0; qx < quads; qx++) {
+                                    double *n_out = out.getSampleDataRW(start + INDEX3(qx, qy, qz, max_x, max_y));
+                                    for (dim_t comp = 0; comp < numComp; comp++) {
+                                        n_out[comp] += e_in[INDEX4(comp, qx, qy, qz, numComp, quads, quads)];
+                                    }
                                 }
                             }
                         }
@@ -1442,10 +1502,39 @@ void Brick::interpolateElementsOnNodes(escript::Data& out,
     }
 }
 
+void Brick::reduceElements(escript::Data& out, const escript::Data& in) const
+{
+    if (m_order == 2) {
+        reduction_order2(in, out);
+    } else if (m_order == 3) {
+        reduction_order3(in, out);
+    } else if (m_order == 4) {
+        reduction_order4(in, out);
+    } else if (m_order == 5) {
+        reduction_order5(in, out);
+    } else if (m_order == 6) {
+        reduction_order6(in, out);
+    } else if (m_order == 7) {
+        reduction_order7(in, out);
+    } else if (m_order == 8) {
+        reduction_order8(in, out);
+    } else if (m_order == 9) {
+        reduction_order9(in, out);
+    } else if (m_order == 10) {
+        reduction_order10(in, out);
+    }
+}
+
 //protected
 void Brick::interpolateNodesOnElements(escript::Data& out,
-                                       const escript::Data& in) const
+                                       const escript::Data& in,
+                                       bool reduced) const
 {
+    if (reduced) { //going to ReducedElements
+        escript::Data funcIn(in, escript::function(*this));
+        reduceElements(out, funcIn);
+        return;
+    }
     const dim_t numComp = in.getDataPointSize();
     const dim_t NE0 = m_NE[0];
     const dim_t NE1 = m_NE[1];
@@ -1773,11 +1862,12 @@ void Brick::shareCorners(escript::Data& out) const
     //setup
     const int tag = 0;
     MPI_Status status;
+    MPI_Request request[8];
     const int numComp = out.getDataPointSize();
     const int count = numComp;
     std::vector<double> inbuf(count, 0);
 
-    //share
+    //send
     for (int z = 0; z < 2; z++) {
         for (int y = 0; y < 2; y++) {
             for (int x = 0; x < 2; x++) {
@@ -1789,8 +1879,26 @@ void Brick::shareCorners(escript::Data& out) const
                                          + z*(m_NN[2]-1)*m_NN[0]*m_NN[1]
                                         );
 
-                    MPI_Sendrecv(data, numComp, MPI_DOUBLE, neighbour_ranks[i], tag,
-                            &inbuf[0], numComp, MPI_DOUBLE, neighbour_ranks[i],
+                    MPI_Isend(data, numComp, MPI_DOUBLE, neighbour_ranks[i], tag,
+                            m_mpiInfo->comm, request+i);
+                }
+            }
+        }
+    }
+
+    //recv
+    for (int z = 0; z < 2; z++) {
+        for (int y = 0; y < 2; y++) {
+            for (int x = 0; x < 2; x++) {
+                int i = INDEX3(x,y,z,2,2);
+                if (neighbour_exists[i]) {
+                    double *data = out.getSampleDataRW(
+                                           x*(m_NN[0]-1)
+                                         + y*(m_NN[1]-1)*m_NN[0]
+                                         + z*(m_NN[2]-1)*m_NN[0]*m_NN[1]
+                                        );
+
+                    MPI_Recv(&inbuf[0], numComp, MPI_DOUBLE, neighbour_ranks[i],
                             tag, m_mpiInfo->comm, &status);
                     //unpack
                     for (int comp = 0; comp < numComp; comp++) {
@@ -1800,6 +1908,13 @@ void Brick::shareCorners(escript::Data& out) const
             }
         }
     }
+
+    //wait
+    for (int i = 0; i < 8; i++) {
+        if (neighbour_exists[i]) {
+            MPI_Wait(request+i, &status);
+        }
+    }
 }
 
 //private
@@ -1808,7 +1923,8 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
     const int rank = m_mpiInfo->rank;
 
     const int tag = 0;
-    MPI_Status status;
+    MPI_Status status[12];
+    MPI_Request request[12];
     const int numComp = out.getDataPointSize();
 
     const bool left = rx;
@@ -1818,12 +1934,12 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
     const bool bottom = rz;
     const bool top = rz < m_NX[2] - 1;
 
-
+    //BEGIN SEND
+    int reqNum = 0;
     if (left) {
         if (front) { //share Z lines
             int neighbour = rank - m_NX[0] - 1;
-            const double count = m_NN[2]*numComp;
-            std::vector<double> buf(count);
+            const dim_t count = m_NN[2]*numComp;
             std::vector<double> outbuf(count);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[2]; i++) {
@@ -1832,20 +1948,12 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
                     outbuf[i*numComp + comp] = data[comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
-            for (dim_t i = 0; i < m_NN[2]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(0, 0, i, m_NN[0], m_NN[1]));
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += buf[i*numComp + comp];
-                }
-            }
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
         }
         if (back) {//share Z lines
             int neighbour = rank + m_NX[0] - 1;
-            const double count = m_NN[2]*numComp;
-            std::vector<double> buf(count);
+            const dim_t count = m_NN[2]*numComp;
             std::vector<double> outbuf(count);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[2]; i++) {
@@ -1854,21 +1962,12 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
                     outbuf[i*numComp + comp] = data[comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
-#pragma omp parallel for
-            for (dim_t i = 0; i < m_NN[2]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(0,m_NN[1]-1,i,m_NN[0],m_NN[1]));
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += buf[i*numComp + comp];
-                }
-            }
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
         }
         if (top) {//share Y lines
             int neighbour = rank + m_NX[0]*m_NX[1] - 1;
-            const double count = m_NN[1]*numComp;
-            std::vector<double> buf(count);
+            const dim_t count = m_NN[1]*numComp;
             std::vector<double> outbuf(count);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[1]; i++) {
@@ -1877,21 +1976,12 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
                     outbuf[i*numComp + comp] = data[comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
-#pragma omp parallel for
-            for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(0,i,m_NN[2]-1,m_NN[0],m_NN[1]));
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += buf[i*numComp + comp];
-                }
-            }
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
         }
         if (bottom) {//share Y lines
             int neighbour = rank - m_NX[0]*m_NX[1] - 1;
-            const double count = m_NN[1]*numComp;
-            std::vector<double> buf(count);
+            const dim_t count = m_NN[1]*numComp;
             std::vector<double> outbuf(count);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[1]; i++) {
@@ -1900,23 +1990,14 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
                     outbuf[i*numComp + comp] = data[comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
-#pragma omp parallel for
-            for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(0,i,0,m_NN[0],m_NN[1]));
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += buf[i*numComp + comp];
-                }
-            }
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
         }
     }
     if (right) {
         if (front) { //share Z lines
             int neighbour = rank - m_NX[0] + 1;
-            const double count = m_NN[2]*numComp;
-            std::vector<double> buf(count);
+            const dim_t count = m_NN[2]*numComp;
             std::vector<double> outbuf(count);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[2]; i++) {
@@ -1926,81 +2007,199 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
                     outbuf[i*numComp + comp] = data[comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+        if (back) {//share Z lines
+            int neighbour = rank + m_NX[0] + 1;
+            const dim_t count = m_NN[2]*numComp;
+            std::vector<double> outbuf(count);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[2]; i++) {
                 double *data = out.getSampleDataRW(
-                            INDEX3(m_NN[0]-1, 0, i, m_NN[0], m_NN[1]));     
+                            INDEX3(m_NN[0]-1, m_NN[1]-1, i, m_NN[0], m_NN[1]));
                 for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += buf[i*numComp + comp];
+                    outbuf[i*numComp + comp] = data[comp];
                 }
             }
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
         }
-        if (back) {//share Z lines
-            int neighbour = rank + m_NX[0] + 1;
-            const double count = m_NN[2]*numComp;
-            std::vector<double> buf(count);
+        if (top) {//share Y lines
+            int neighbour = rank + m_NX[0]*m_NX[1] + 1;
+            const dim_t count = m_NN[1]*numComp;
             std::vector<double> outbuf(count);
 #pragma omp parallel for
-            for (dim_t i = 0; i < m_NN[2]; i++) {
-                double *data = out.getSampleDataRW(
-                            INDEX3(m_NN[0]-1, m_NN[1]-1, i, m_NN[0], m_NN[1]));
+            for (dim_t i = 0; i < m_NN[1]; i++) {
+                double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,m_NN[2]-1,m_NN[0],m_NN[1]));
                 for (int comp = 0; comp < numComp; comp++) {
                     outbuf[i*numComp + comp] = data[comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+        if (bottom) {//share Y lines
+            int neighbour = rank - m_NX[0]*m_NX[1] + 1;
+            const dim_t count = m_NN[1]*numComp;
+            std::vector<double> outbuf(count);
+#pragma omp parallel for
+            for (dim_t i = 0; i < m_NN[1]; i++) {
+                double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,0,m_NN[0],m_NN[1]));
+                for (int comp = 0; comp < numComp; comp++) {
+                    outbuf[i*numComp + comp] = data[comp];
+                }
+            }
+            MPI_Isend(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+    }
+
+    if (top) {
+        const dim_t count = m_NN[0]*numComp;
+        std::vector<double> buf(count);
+        if (front) {//share X lines
+            int neighbour = rank + m_NX[0]*m_NX[1] - m_NX[0];
+            double *data = out.getSampleDataRW(m_NN[0]*m_NN[1]*(m_NN[2]-1));
+            MPI_Isend(data, count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+        if (back) {//share X lines
+            int neighbour = rank + m_NX[0]*m_NX[1] + m_NX[0];
+            double *data = out.getSampleDataRW(m_NN[0]*m_NN[1]*(m_NN[2]-1)
+                                             + m_NN[0]*(m_NN[1]-1));
+            MPI_Isend(data, count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+    }
+    if (bottom) {
+        const dim_t count = m_NN[0]*numComp;
+        std::vector<double> buf(count);
+        if (front) {//share X lines
+            int neighbour = rank - m_NX[0]*m_NX[1] - m_NX[0];
+            double *data = out.getSampleDataRW(0);
+            MPI_Isend(data, count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+        if (back) {//share X lines
+            int neighbour = rank - m_NX[0]*m_NX[1] + m_NX[0];
+            double *data = out.getSampleDataRW(m_NN[0]*(m_NN[1]-1));
+            MPI_Isend(data, count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, request + reqNum++);
+        }
+    }
+    //END SEND
+    
+    //BEGIN RECV
+    if (left) {
+        if (front) { //share Z lines
+            int neighbour = rank - m_NX[0] - 1;
+            const dim_t count = m_NN[2]*numComp;
+            std::vector<double> buf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
+            for (dim_t i = 0; i < m_NN[2]; i++) {
+                double *data = out.getSampleDataRW(INDEX3(0, 0, i, m_NN[0], m_NN[1]));
+                for (int comp = 0; comp < numComp; comp++) {
+                    data[comp] += buf[i*numComp + comp];
+                }
+            }
+        }
+        if (back) {//share Z lines
+            int neighbour = rank + m_NX[0] - 1;
+            const dim_t count = m_NN[2]*numComp;
+            std::vector<double> buf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[2]; i++) {
-                double *data = out.getSampleDataRW(
-                            INDEX3(m_NN[0]-1, m_NN[1]-1, i, m_NN[0], m_NN[1]));
+                double *data = out.getSampleDataRW(INDEX3(0,m_NN[1]-1,i,m_NN[0],m_NN[1]));
                 for (int comp = 0; comp < numComp; comp++) {
                     data[comp] += buf[i*numComp + comp];
                 }
             }
         }
         if (top) {//share Y lines
-            int neighbour = rank + m_NX[0]*m_NX[1] + 1;
-            const double count = m_NN[1]*numComp;
+            int neighbour = rank + m_NX[0]*m_NX[1] - 1;
+            const dim_t count = m_NN[1]*numComp;
             std::vector<double> buf(count);
-            std::vector<double> outbuf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,m_NN[2]-1,m_NN[0],m_NN[1]));
+                double *data = out.getSampleDataRW(INDEX3(0,i,m_NN[2]-1,m_NN[0],m_NN[1]));
                 for (int comp = 0; comp < numComp; comp++) {
-                    outbuf[i*numComp + comp] = data[comp];
+                    data[comp] += buf[i*numComp + comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+        }
+        if (bottom) {//share Y lines
+            int neighbour = rank - m_NX[0]*m_NX[1] - 1;
+            const dim_t count = m_NN[1]*numComp;
+            std::vector<double> buf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,m_NN[2]-1,m_NN[0],m_NN[1]));
+                double *data = out.getSampleDataRW(INDEX3(0,i,0,m_NN[0],m_NN[1]));
                 for (int comp = 0; comp < numComp; comp++) {
                     data[comp] += buf[i*numComp + comp];
                 }
             }
         }
-        if (bottom) {//share Y lines
-            int neighbour = rank - m_NX[0]*m_NX[1] + 1;
-            const double count = m_NN[1]*numComp;
+    }
+    if (right) {
+        if (front) { //share Z lines
+            int neighbour = rank - m_NX[0] + 1;
+            const dim_t count = m_NN[2]*numComp;
             std::vector<double> buf(count);
-            std::vector<double> outbuf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
+            for (dim_t i = 0; i < m_NN[2]; i++) {
+                double *data = out.getSampleDataRW(
+                            INDEX3(m_NN[0]-1, 0, i, m_NN[0], m_NN[1]));     
+                for (int comp = 0; comp < numComp; comp++) {
+                    data[comp] += buf[i*numComp + comp];
+                }
+            }
+        }
+        if (back) {//share Z lines
+            int neighbour = rank + m_NX[0] + 1;
+            const dim_t count = m_NN[2]*numComp;
+            std::vector<double> buf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
+            for (dim_t i = 0; i < m_NN[2]; i++) {
+                double *data = out.getSampleDataRW(
+                            INDEX3(m_NN[0]-1, m_NN[1]-1, i, m_NN[0], m_NN[1]));
+                for (int comp = 0; comp < numComp; comp++) {
+                    data[comp] += buf[i*numComp + comp];
+                }
+            }
+        }
+        if (top) {//share Y lines
+            int neighbour = rank + m_NX[0]*m_NX[1] + 1;
+            const dim_t count = m_NN[1]*numComp;
+            std::vector<double> buf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,0,m_NN[0],m_NN[1]));
+                double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,m_NN[2]-1,m_NN[0],m_NN[1]));
                 for (int comp = 0; comp < numComp; comp++) {
-                    outbuf[i*numComp + comp] = data[comp];
+                    data[comp] += buf[i*numComp + comp];
                 }
             }
-            MPI_Sendrecv(&outbuf[0], count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+        }
+        if (bottom) {//share Y lines
+            int neighbour = rank - m_NX[0]*m_NX[1] + 1;
+            const dim_t count = m_NN[1]*numComp;
+            std::vector<double> buf(count);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
 #pragma omp parallel for
             for (dim_t i = 0; i < m_NN[1]; i++) {
                 double *data = out.getSampleDataRW(INDEX3(m_NN[0]-1,i,0,m_NN[0],m_NN[1]));
@@ -2012,14 +2211,14 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
     }
 
     if (top) {
-        const double count = m_NN[0]*numComp;
+        const dim_t count = m_NN[0]*numComp;
         std::vector<double> buf(count);
         if (front) {//share X lines
             int neighbour = rank + m_NX[0]*m_NX[1] - m_NX[0];
             double *data = out.getSampleDataRW(m_NN[0]*m_NN[1]*(m_NN[2]-1));
-                MPI_Sendrecv(data, count, MPI_DOUBLE, neighbour, tag,
-                                &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                                m_mpiInfo->comm, &status);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
             for (dim_t i = 0; i < count; i++) {
                 data[i] += buf[i];
             }
@@ -2028,23 +2227,23 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
             int neighbour = rank + m_NX[0]*m_NX[1] + m_NX[0];
             double *data = out.getSampleDataRW(m_NN[0]*m_NN[1]*(m_NN[2]-1)
                                              + m_NN[0]*(m_NN[1]-1));
-            MPI_Sendrecv(data, count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
             for (dim_t i = 0; i < count; i++) {
                 data[i] += buf[i];
             }
         }
     }
     if (bottom) {
-        const double count = m_NN[0]*numComp;
+        const dim_t count = m_NN[0]*numComp;
         std::vector<double> buf(count);
         if (front) {//share X lines
             int neighbour = rank - m_NX[0]*m_NX[1] - m_NX[0];
             double *data = out.getSampleDataRW(0);
-            MPI_Sendrecv(data, count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
             for (dim_t i = 0; i < count; i++) {
                 data[i] += buf[i];
             }
@@ -2052,20 +2251,23 @@ void Brick::shareEdges(escript::Data& out, int rx, int ry, int rz) const
         if (back) {//share X lines
             int neighbour = rank - m_NX[0]*m_NX[1] + m_NX[0];
             double *data = out.getSampleDataRW(m_NN[0]*(m_NN[1]-1));
-            MPI_Sendrecv(data, count, MPI_DOUBLE, neighbour, tag,
-                            &buf[0], count, MPI_DOUBLE, neighbour, tag,
-                            m_mpiInfo->comm, &status);
+            MPI_Recv(&buf[0], count, MPI_DOUBLE, neighbour, tag,
+                    m_mpiInfo->comm, status);
+#pragma omp parallel for
             for (dim_t i = 0; i < count; i++) {
                 data[i] += buf[i];
             }
         }
     }
+    //END RECV
+    
+    //finally, wait for all those Isends to be complete
+    MPI_Waitall(reqNum, request, status);
 }
 
 
 void frontAndBack(escript::Data& out, int ry, const int numComp, int rank,
                     const dim_t NN[3], const int NX[3], MPI_Comm& comm) {
-    const int tag = 0;
     MPI_Status status;
     const int front_neighbour = rank - NX[0];
     const int back_neighbour = rank + NX[0];
@@ -2084,10 +2286,21 @@ void frontAndBack(escript::Data& out, int ry, const int numComp, int rank,
             std::copy(backData, backData + numComp, &back[index]);
         }
     }
+
+    MPI_Request request[2];
+    if (ry) {
+        MPI_Isend(&front[0], count, MPI_DOUBLE, front_neighbour, rank,
+            comm, request);
+    }
+    
+    if (ry < NX[1] - 1) {
+        MPI_Isend(&back[0], count, MPI_DOUBLE, back_neighbour, rank,
+            comm, request+1);
+    }
+    
     //front
     if (ry) {
-        MPI_Sendrecv(&front[0], count, MPI_DOUBLE, front_neighbour, tag,
-                    &recv[0], count, MPI_DOUBLE, front_neighbour, tag,
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, front_neighbour, front_neighbour,
                     comm, &status);
         //unpack front
 #pragma omp parallel for
@@ -2104,8 +2317,7 @@ void frontAndBack(escript::Data& out, int ry, const int numComp, int rank,
 
     //back
     if (ry < NX[1] - 1) {
-        MPI_Sendrecv(&back[0], count, MPI_DOUBLE, back_neighbour, tag,
-                &recv[0], count, MPI_DOUBLE, back_neighbour, tag,
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, back_neighbour, back_neighbour,
                 comm, &status);
         //unpack back
 #pragma omp parallel for
@@ -2119,11 +2331,17 @@ void frontAndBack(escript::Data& out, int ry, const int numComp, int rank,
             }
         }
     }
+    
+    if (ry) {
+        MPI_Wait(request, &status);
+    }
+    if (ry < NX[1] - 1) {
+        MPI_Wait(request+1, &status);
+    }
 }
 
 void topAndBottom(escript::Data& out, int rz, int numComp, int rank,
                     const dim_t NN[3], const int NX[3], MPI_Comm& comm) {
-    const int tag = 0;
     MPI_Status status;
     const int top_neighbour = rank + NX[0]*NX[1];
     const int bottom_neighbour = rank - NX[0]*NX[1];
@@ -2143,11 +2361,21 @@ void topAndBottom(escript::Data& out, int rz, int numComp, int rank,
         }
     }
 
+    MPI_Request request[2];
+    if (rz) {
+        MPI_Isend(&bottom[0], count, MPI_DOUBLE, bottom_neighbour, rank,
+            comm, request);
+    }
+   
+    if (rz < NX[2] - 1) {
+        MPI_Isend(&top[0], count, MPI_DOUBLE, top_neighbour, rank,
+            comm, request + 1);
+    }
+
     //bottom
     if (rz) {
-        MPI_Sendrecv(&bottom[0], count, MPI_DOUBLE, bottom_neighbour, tag,
-                    &recv[0], count, MPI_DOUBLE, bottom_neighbour, tag,
-                    comm, &status);
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, bottom_neighbour,
+                bottom_neighbour, comm, &status);
         //unpack to bottom
 #pragma omp parallel for
         for (dim_t y = 0; y < NN[1]; y++) {
@@ -2163,8 +2391,7 @@ void topAndBottom(escript::Data& out, int rz, int numComp, int rank,
 
     //top
     if (rz < NX[2] - 1) {
-        MPI_Sendrecv(&top[0], count, MPI_DOUBLE, top_neighbour, tag,
-                    &recv[0], count, MPI_DOUBLE, top_neighbour, tag,
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, top_neighbour, top_neighbour,
                     comm, &status);
         //unpack to top
 #pragma omp parallel for
@@ -2178,12 +2405,17 @@ void topAndBottom(escript::Data& out, int rz, int numComp, int rank,
             }
         }
     }
+    if (rz) {
+        MPI_Wait(request, &status);
+    }
+    if (rz < NX[2] - 1) {
+        MPI_Wait(request+1, &status);
+    }
 }
 
 
 void leftAndRight(escript::Data& out, int rx, int numComp, int rank,
                     const dim_t NN[3], const int NX[3], MPI_Comm& comm) {
-    const int tag = 0;
     MPI_Status status;
     const int left_neighbour = rank - 1;
     const int right_neighbour = rank + 1;
@@ -2204,10 +2436,22 @@ void leftAndRight(escript::Data& out, int rx, int numComp, int rank,
 
     }
 
-    //right
+    MPI_Request request[2];
+
+    //right send
     if (rx < NX[0] - 1) {
-        MPI_Sendrecv(&right[0], count, MPI_DOUBLE, right_neighbour, tag,
-                &recv[0], count, MPI_DOUBLE, right_neighbour, tag,
+        MPI_Isend(&right[0], count, MPI_DOUBLE, right_neighbour,
+                rank, comm, request);
+    }
+    //left send
+    if (rx) {
+        MPI_Isend(&left[0], count, MPI_DOUBLE, left_neighbour,
+                rank, comm, request+1);
+    }
+    
+    //right recv
+    if (rx < NX[0] - 1) {    
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, right_neighbour, right_neighbour,
                 comm, &status);
         //unpack to right
 #pragma omp parallel for
@@ -2223,9 +2467,8 @@ void leftAndRight(escript::Data& out, int rx, int numComp, int rank,
     }
     //left
     if (rx) {
-        MPI_Sendrecv(&left[0], count, MPI_DOUBLE, left_neighbour, tag,
-                    &recv[0], count, MPI_DOUBLE, left_neighbour, tag,
-                    comm, &status);
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, left_neighbour, left_neighbour,
+                comm, &status);
         //unpack to left
 #pragma omp parallel for
         for (dim_t z = 0; z < NN[2]; z++) {
@@ -2238,6 +2481,12 @@ void leftAndRight(escript::Data& out, int rx, int numComp, int rank,
             }
         }
     }
+    if (rx) {
+        MPI_Wait(request+1, &status);
+    }
+    if (rx < NX[0] - 1) {
+        MPI_Wait(request, &status);
+    }
 }
 
 
@@ -2345,6 +2594,8 @@ Assembler_ptr Brick::createAssembler(std::string type,
     if (type.compare("DefaultAssembler") == 0) {
         return Assembler_ptr(new DefaultAssembler3D(shared_from_this(), m_dx,
                 m_NE, m_NN));
+    } else if (type.compare("WaveAssembler") == 0) {
+        return Assembler_ptr(new WaveAssembler3D(shared_from_this(), m_dx, m_NE, m_NN, options));
     } else { //else ifs would go before this for other types
         throw SpeckleyException("Speckley::Brick does not support the"
                                 " requested assembler");
diff --git a/speckley/src/Brick.h b/speckley/src/Brick.h
index 9655c22..90cf747 100644
--- a/speckley/src/Brick.h
+++ b/speckley/src/Brick.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -32,6 +32,7 @@ class RipleyCoupler; //forward declaration of coupler to avoid circles
 class Speckley_DLL_API Brick: public SpeckleyDomain
 {
     friend class DefaultAssembler3D;
+    friend class WaveAssembler3D;
 public:
 
     /**
@@ -224,11 +225,13 @@ protected:
     virtual void assembleIntegrate(DoubleVector& integrals,
                                    const escript::Data& arg) const;
     virtual void interpolateNodesOnElements(escript::Data& out,
-                                  const escript::Data& in) const;
+                                  const escript::Data& in,
+                                  bool reduced) const;
     virtual void interpolateElementsOnNodes(escript::Data& out,
                                 const escript::Data& in) const;
     virtual dim_t getDofOfNode(dim_t node) const;
     Assembler_ptr createAssembler(std::string type, const DataMap& constants) const;
+    virtual void reduceElements(escript::Data& out, const escript::Data& in) const;
 #ifdef ESYS_MPI
     virtual void balanceNeighbours(escript::Data& data, bool average) const;
 #endif
@@ -244,6 +247,16 @@ private:
     void gradient_order9(escript::Data&, const escript::Data&) const;
     void gradient_order10(escript::Data&, const escript::Data&) const;
 
+    void reduction_order2(const escript::Data&, escript::Data&) const;
+    void reduction_order3(const escript::Data&, escript::Data&) const;
+    void reduction_order4(const escript::Data&, escript::Data&) const;
+    void reduction_order5(const escript::Data&, escript::Data&) const;
+    void reduction_order6(const escript::Data&, escript::Data&) const;
+    void reduction_order7(const escript::Data&, escript::Data&) const;
+    void reduction_order8(const escript::Data&, escript::Data&) const;
+    void reduction_order9(const escript::Data&, escript::Data&) const;
+    void reduction_order10(const escript::Data&, escript::Data&) const;
+
     void integral_order2(std::vector<double>&, const escript::Data&) const;
     void integral_order3(std::vector<double>&, const escript::Data&) const;
     void integral_order4(std::vector<double>&, const escript::Data&) const;
diff --git a/speckley/src/BrickGradients.cpp b/speckley/src/BrickGradients.cpp
index f9ff614..d19a432 100644
--- a/speckley/src/BrickGradients.cpp
+++ b/speckley/src/BrickGradients.cpp
@@ -1,3 +1,21 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 #include <esysUtils/index.h>
 #include <speckley/Brick.h>
 
@@ -17,27 +35,16 @@ void Brick::gradient_order2(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 3; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 3; ++k) {
                             for (int j = 0; j < 3; ++j) {
-                                for (int k = 0; k < 3; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,3,3)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,3,3)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,3,3)] = c;
+                                for (int i = 0; i < 3; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,3,3);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -52,28 +59,13 @@ void Brick::gradient_order2(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 3; ++i) {
+                    for (int k = 0; k < 3; ++k) {
                         for (int j = 0; j < 3; ++j) {
-                            for (int k = 0; k < 3; ++k) {
+                            for (int i = 0; i < 3; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,3,3)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,3,3)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,3,3)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,3,3)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,3,3)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,3,3)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,3,3)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,3,3)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,3,3)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,3,3)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,3,3)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,3,3)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,3,3)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,3,3)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,3,3)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,3,3)]) * inv_jac[0];
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,3,3)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,3,3)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,3,3)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,3,3)]) * inv_jac[1];
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,3,3)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,3,3)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,3,3)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,3,3)]) * inv_jac[2];
                                 }
                             }
                         }
@@ -93,8 +85,6 @@ void Brick::gradient_order3(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 16 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -102,30 +92,16 @@ void Brick::gradient_order3(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 4; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 4; ++k) {
                             for (int j = 0; j < 4; ++j) {
-                                for (int k = 0; k < 4; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,4,4)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,4,4)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,4,4)] = c;
+                                for (int i = 0; i < 4; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,4,4);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -140,31 +116,13 @@ void Brick::gradient_order3(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 4; ++i) {
+                    for (int k = 0; k < 4; ++k) {
                         for (int j = 0; j < 4; ++j) {
-                            for (int k = 0; k < 4; ++k) {
+                            for (int i = 0; i < 4; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,4,4)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,4,4)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,4,4)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,4,4)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,4,4)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,4,4)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,4,4)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,4,4)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,4,4)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,4,4)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,4,4)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,4,4)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,4,4)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,4,4)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,4,4)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,4,4)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,4,4)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,4,4)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,4,4)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,4,4)]) * inv_jac[0];
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,4,4)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,4,4)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,4,4)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,4,4)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,4,4)]) * inv_jac[1];
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,4,4)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,4,4)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,4,4)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,4,4)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,4,4)]) * inv_jac[2];
                                 }
                             }
                         }
@@ -187,8 +145,6 @@ void Brick::gradient_order4(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 25 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -196,33 +152,16 @@ void Brick::gradient_order4(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 5; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 5; ++k) {
                             for (int j = 0; j < 5; ++j) {
-                                for (int k = 0; k < 5; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,5,5)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,5,5)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,5,5)] = c;
+                                for (int i = 0; i < 5; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,5,5);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -237,34 +176,13 @@ void Brick::gradient_order4(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 5; ++i) {
+                    for (int k = 0; k < 5; ++k) {
                         for (int j = 0; j < 5; ++j) {
-                            for (int k = 0; k < 5; ++k) {
+                            for (int i = 0; i < 5; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,5,5)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,5,5)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,5,5)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,5,5)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,5,5)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,5,5)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,5,5)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,5,5)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,5,5)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,5,5)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,5,5)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,5,5)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,5,5)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,5,5)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,5,5)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,5,5)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,5,5)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,5,5)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,5,5)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,5,5)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,5,5)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,5,5)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,5,5)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,5,5)]) * inv_jac[0];
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,5,5)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,5,5)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,5,5)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,5,5)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,5,5)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,5,5)]) * inv_jac[1];
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,5,5)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,5,5)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,5,5)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,5,5)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,5,5)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,5,5)]) * inv_jac[2];
                                 }
                             }
                         }
@@ -288,8 +206,6 @@ void Brick::gradient_order5(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 36 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -297,36 +213,16 @@ void Brick::gradient_order5(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a += lagrange_deriv_5[0] * e[comp];
-                        b += lagrange_deriv_5[0] * e[comp];
-                        c += lagrange_deriv_5[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 6; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 6; ++k) {
                             for (int j = 0; j < 6; ++j) {
-                                for (int k = 0; k < 6; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,6,6)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,6,6)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,6,6)] = c;
+                                for (int i = 0; i < 6; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,6,6);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -341,37 +237,13 @@ void Brick::gradient_order5(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 6; ++i) {
+                    for (int k = 0; k < 6; ++k) {
                         for (int j = 0; j < 6; ++j) {
-                            for (int k = 0; k < 6; ++k) {
+                            for (int i = 0; i < 6; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,6,6)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,6,6)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,6,6)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,6,6)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,6,6)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,6,6)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,6,6)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,6,6)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,6,6)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,6,6)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,6,6)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,6,6)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,6,6)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,6,6)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,6,6)];
-                                    a += lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,6,6)];
-                                    b += lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,6,6)];
-                                    c += lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,6,6)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,6,6)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,6,6)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,6,6)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,6,6)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,6,6)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,6,6)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,6,6)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,6,6)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,6,6)] + lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,6,6)]) * inv_jac[0];
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,6,6)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,6,6)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,6,6)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,6,6)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,6,6)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,6,6)] + lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,6,6)]) * inv_jac[1];
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,6,6)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,6,6)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,6,6)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,6,6)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,6,6)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,6,6)] + lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,6,6)]) * inv_jac[2];
                                 }
                             }
                         }
@@ -396,8 +268,6 @@ void Brick::gradient_order6(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 49 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -405,39 +275,16 @@ void Brick::gradient_order6(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a += lagrange_deriv_5[0] * e[comp];
-                        b += lagrange_deriv_5[0] * e[comp];
-                        c += lagrange_deriv_5[0] * e[comp];
-                        a += lagrange_deriv_6[0] * e[comp];
-                        b += lagrange_deriv_6[0] * e[comp];
-                        c += lagrange_deriv_6[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 7; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 7; ++k) {
                             for (int j = 0; j < 7; ++j) {
-                                for (int k = 0; k < 7; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,7,7)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,7,7)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,7,7)] = c;
+                                for (int i = 0; i < 7; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,7,7);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -452,40 +299,13 @@ void Brick::gradient_order6(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 7; ++i) {
+                    for (int k = 0; k < 7; ++k) {
                         for (int j = 0; j < 7; ++j) {
-                            for (int k = 0; k < 7; ++k) {
+                            for (int i = 0; i < 7; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,7,7)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,7,7)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,7,7)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,7,7)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,7,7)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,7,7)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,7,7)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,7,7)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,7,7)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,7,7)];
-                                    a += lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,7,7)];
-                                    c += lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,7,7)];
-                                    a += lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,7,7)];
-                                    b += lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,7,7)];
-                                    c += lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,7,7)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,7,7)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,7,7)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,7,7)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,7,7)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,7,7)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,7,7)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,7,7)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,7,7)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,7,7)] + lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,7,7)] + lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,7,7)]) * inv_jac[0];
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,7,7)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,7,7)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,7,7)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,7,7)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,7,7)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,7,7)] + lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,7,7)] + lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,7,7)]) * inv_jac[1];
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,7,7)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,7,7)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,7,7)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,7,7)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,7,7)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,7,7)] + lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,7,7)] + lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,7,7)]) * inv_jac[2];
                                 }
                             }
                         }
@@ -511,8 +331,6 @@ void Brick::gradient_order7(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 64 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -520,42 +338,16 @@ void Brick::gradient_order7(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a += lagrange_deriv_5[0] * e[comp];
-                        b += lagrange_deriv_5[0] * e[comp];
-                        c += lagrange_deriv_5[0] * e[comp];
-                        a += lagrange_deriv_6[0] * e[comp];
-                        b += lagrange_deriv_6[0] * e[comp];
-                        c += lagrange_deriv_6[0] * e[comp];
-                        a += lagrange_deriv_7[0] * e[comp];
-                        b += lagrange_deriv_7[0] * e[comp];
-                        c += lagrange_deriv_7[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 8; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 8; ++k) {
                             for (int j = 0; j < 8; ++j) {
-                                for (int k = 0; k < 8; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,8,8)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,8,8)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,8,8)] = c;
+                                for (int i = 0; i < 8; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,8,8);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -570,43 +362,13 @@ void Brick::gradient_order7(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 8; ++i) {
+                    for (int k = 0; k < 8; ++k) {
                         for (int j = 0; j < 8; ++j) {
-                            for (int k = 0; k < 8; ++k) {
+                            for (int i = 0; i < 8; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,8,8)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,8,8)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,8,8)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,8,8)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,8,8)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,8,8)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,8,8)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,8,8)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,8,8)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,8,8)];
-                                    a += lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,8,8)];
-                                    c += lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,8,8)];
-                                    a += lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,8,8)];
-                                    c += lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,8,8)];
-                                    a += lagrange_deriv_7[i] * e[INDEX4(comp,7,j,k,numComp,8,8)];
-                                    b += lagrange_deriv_7[j] * e[INDEX4(comp,i,7,k,numComp,8,8)];
-                                    c += lagrange_deriv_7[k] * e[INDEX4(comp,i,j,7,numComp,8,8)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,8,8)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,8,8)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,8,8)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,8,8)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,8,8)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,8,8)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,8,8)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,8,8)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,8,8)] + lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,8,8)] + lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,8,8)] + lagran [...]
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,8,8)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,8,8)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,8,8)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,8,8)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,8,8)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,8,8)] + lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,8,8)] + lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,8,8)] + lagran [...]
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,8,8)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,8,8)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,8,8)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,8,8)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,8,8)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,8,8)] + lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,8,8)] + lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,8,8)] + lagran [...]
                                 }
                             }
                         }
@@ -633,8 +395,6 @@ void Brick::gradient_order8(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 81 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -642,45 +402,16 @@ void Brick::gradient_order8(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a += lagrange_deriv_5[0] * e[comp];
-                        b += lagrange_deriv_5[0] * e[comp];
-                        c += lagrange_deriv_5[0] * e[comp];
-                        a += lagrange_deriv_6[0] * e[comp];
-                        b += lagrange_deriv_6[0] * e[comp];
-                        c += lagrange_deriv_6[0] * e[comp];
-                        a += lagrange_deriv_7[0] * e[comp];
-                        b += lagrange_deriv_7[0] * e[comp];
-                        c += lagrange_deriv_7[0] * e[comp];
-                        a += lagrange_deriv_8[0] * e[comp];
-                        b += lagrange_deriv_8[0] * e[comp];
-                        c += lagrange_deriv_8[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 9; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 9; ++k) {
                             for (int j = 0; j < 9; ++j) {
-                                for (int k = 0; k < 9; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,9,9)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,9,9)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,9,9)] = c;
+                                for (int i = 0; i < 9; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,9,9);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -695,46 +426,13 @@ void Brick::gradient_order8(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 9; ++i) {
+                    for (int k = 0; k < 9; ++k) {
                         for (int j = 0; j < 9; ++j) {
-                            for (int k = 0; k < 9; ++k) {
+                            for (int i = 0; i < 9; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,9,9)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,9,9)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,9,9)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,9,9)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,9,9)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,9,9)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,9,9)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,9,9)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,9,9)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,9,9)];
-                                    a += lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,9,9)];
-                                    c += lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,9,9)];
-                                    a += lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,9,9)];
-                                    c += lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,9,9)];
-                                    a += lagrange_deriv_7[i] * e[INDEX4(comp,7,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_7[j] * e[INDEX4(comp,i,7,k,numComp,9,9)];
-                                    c += lagrange_deriv_7[k] * e[INDEX4(comp,i,j,7,numComp,9,9)];
-                                    a += lagrange_deriv_8[i] * e[INDEX4(comp,8,j,k,numComp,9,9)];
-                                    b += lagrange_deriv_8[j] * e[INDEX4(comp,i,8,k,numComp,9,9)];
-                                    c += lagrange_deriv_8[k] * e[INDEX4(comp,i,j,8,numComp,9,9)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,9,9)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,9,9)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,9,9)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,9,9)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,9,9)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,9,9)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,9,9)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,9,9)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,9,9)] + lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,9,9)] + lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,9,9)] + lagran [...]
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,9,9)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,9,9)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,9,9)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,9,9)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,9,9)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,9,9)] + lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,9,9)] + lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,9,9)] + lagran [...]
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,9,9)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,9,9)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,9,9)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,9,9)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,9,9)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,9,9)] + lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,9,9)] + lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,9,9)] + lagran [...]
                                 }
                             }
                         }
@@ -762,8 +460,6 @@ void Brick::gradient_order9(escript::Data& out, const escript::Data& in) const {
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 100 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -771,48 +467,16 @@ void Brick::gradient_order9(escript::Data& out, const escript::Data& in) const {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a += lagrange_deriv_5[0] * e[comp];
-                        b += lagrange_deriv_5[0] * e[comp];
-                        c += lagrange_deriv_5[0] * e[comp];
-                        a += lagrange_deriv_6[0] * e[comp];
-                        b += lagrange_deriv_6[0] * e[comp];
-                        c += lagrange_deriv_6[0] * e[comp];
-                        a += lagrange_deriv_7[0] * e[comp];
-                        b += lagrange_deriv_7[0] * e[comp];
-                        c += lagrange_deriv_7[0] * e[comp];
-                        a += lagrange_deriv_8[0] * e[comp];
-                        b += lagrange_deriv_8[0] * e[comp];
-                        c += lagrange_deriv_8[0] * e[comp];
-                        a += lagrange_deriv_9[0] * e[comp];
-                        b += lagrange_deriv_9[0] * e[comp];
-                        c += lagrange_deriv_9[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 10; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 10; ++k) {
                             for (int j = 0; j < 10; ++j) {
-                                for (int k = 0; k < 10; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,10,10)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,10,10)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,10,10)] = c;
+                                for (int i = 0; i < 10; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,10,10);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -827,49 +491,13 @@ void Brick::gradient_order9(escript::Data& out, const escript::Data& in) const {
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 10; ++i) {
+                    for (int k = 0; k < 10; ++k) {
                         for (int j = 0; j < 10; ++j) {
-                            for (int k = 0; k < 10; ++k) {
+                            for (int i = 0; i < 10; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,10,10)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,10,10)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,10,10)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,10,10)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,10,10)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,10,10)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,10,10)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,10,10)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,10,10)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,10,10)];
-                                    a += lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,10,10)];
-                                    c += lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,10,10)];
-                                    a += lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,10,10)];
-                                    c += lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,10,10)];
-                                    a += lagrange_deriv_7[i] * e[INDEX4(comp,7,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_7[j] * e[INDEX4(comp,i,7,k,numComp,10,10)];
-                                    c += lagrange_deriv_7[k] * e[INDEX4(comp,i,j,7,numComp,10,10)];
-                                    a += lagrange_deriv_8[i] * e[INDEX4(comp,8,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_8[j] * e[INDEX4(comp,i,8,k,numComp,10,10)];
-                                    c += lagrange_deriv_8[k] * e[INDEX4(comp,i,j,8,numComp,10,10)];
-                                    a += lagrange_deriv_9[i] * e[INDEX4(comp,9,j,k,numComp,10,10)];
-                                    b += lagrange_deriv_9[j] * e[INDEX4(comp,i,9,k,numComp,10,10)];
-                                    c += lagrange_deriv_9[k] * e[INDEX4(comp,i,j,9,numComp,10,10)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,10,10)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,10,10)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,10,10)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,10,10)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,10,10)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,10,10)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,10,10)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,10,10)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,10,10)] + lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,10,10)] + lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp, [...]
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,10,10)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,10,10)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,10,10)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,10,10)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,10,10)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,10,10)] + lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,10,10)] + lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp, [...]
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,10,10)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,10,10)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,10,10)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,10,10)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,10,10)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,10,10)] + lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,10,10)] + lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp, [...]
                                 }
                             }
                         }
@@ -898,8 +526,6 @@ void Brick::gradient_order10(escript::Data& out, const escript::Data& in) const
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 121 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[2]; ++ei) {
             for (int ej = 0; ej < m_NE[1]; ++ej) {
@@ -907,51 +533,16 @@ void Brick::gradient_order10(escript::Data& out, const escript::Data& in) const
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     for (int comp = 0; comp < numComp; ++comp) {
-                        double a = 0;
-                        double b = 0;
-                        double c = 0;
-                        a += lagrange_deriv_0[0] * e[comp];
-                        b += lagrange_deriv_0[0] * e[comp];
-                        c += lagrange_deriv_0[0] * e[comp];
-                        a += lagrange_deriv_1[0] * e[comp];
-                        b += lagrange_deriv_1[0] * e[comp];
-                        c += lagrange_deriv_1[0] * e[comp];
-                        a += lagrange_deriv_2[0] * e[comp];
-                        b += lagrange_deriv_2[0] * e[comp];
-                        c += lagrange_deriv_2[0] * e[comp];
-                        a += lagrange_deriv_3[0] * e[comp];
-                        b += lagrange_deriv_3[0] * e[comp];
-                        c += lagrange_deriv_3[0] * e[comp];
-                        a += lagrange_deriv_4[0] * e[comp];
-                        b += lagrange_deriv_4[0] * e[comp];
-                        c += lagrange_deriv_4[0] * e[comp];
-                        a += lagrange_deriv_5[0] * e[comp];
-                        b += lagrange_deriv_5[0] * e[comp];
-                        c += lagrange_deriv_5[0] * e[comp];
-                        a += lagrange_deriv_6[0] * e[comp];
-                        b += lagrange_deriv_6[0] * e[comp];
-                        c += lagrange_deriv_6[0] * e[comp];
-                        a += lagrange_deriv_7[0] * e[comp];
-                        b += lagrange_deriv_7[0] * e[comp];
-                        c += lagrange_deriv_7[0] * e[comp];
-                        a += lagrange_deriv_8[0] * e[comp];
-                        b += lagrange_deriv_8[0] * e[comp];
-                        c += lagrange_deriv_8[0] * e[comp];
-                        a += lagrange_deriv_9[0] * e[comp];
-                        b += lagrange_deriv_9[0] * e[comp];
-                        c += lagrange_deriv_9[0] * e[comp];
-                        a += lagrange_deriv_10[0] * e[comp];
-                        b += lagrange_deriv_10[0] * e[comp];
-                        c += lagrange_deriv_10[0] * e[comp];
-                        a *= inv_jac[0];
-                        b *= inv_jac[1];
-                        c *= inv_jac[2];
-                        for (int i = 0; i < 11; ++i) {
+                        const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp] + lagrange_deriv_10[0] * e[comp]) * inv_jac[0];
+                        const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp] + lagrange_deriv_10[0] * e[comp]) * inv_jac[1];
+                        const double c = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp] + lagrange_deriv_10[0] * e[comp]) * inv_jac[2];
+                        for (int k = 0; k < 11; ++k) {
                             for (int j = 0; j < 11; ++j) {
-                                for (int k = 0; k < 11; ++k) {
-                                    grad[INDEX5(0,comp,k,j,i,3,numComp,11,11)] = a;
-                                    grad[INDEX5(1,comp,k,j,i,3,numComp,11,11)] = b;
-                                    grad[INDEX5(2,comp,k,j,i,3,numComp,11,11)] = c;
+                                for (int i = 0; i < 11; ++i) {
+                                    const index_t ind = INDEX5(0,comp,i,j,k,3,numComp,11,11);
+                                    grad[ind + 0] = a;
+                                    grad[ind + 1] = b;
+                                    grad[ind + 2] = c;
                                 }
                             }
                         }
@@ -966,52 +557,13 @@ void Brick::gradient_order10(escript::Data& out, const escript::Data& in) const
                 for (int ek = 0; ek < m_NE[0]; ++ek) {
                     const double *e = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                     double *grad = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                    for (int i = 0; i < 11; ++i) {
+                    for (int k = 0; k < 11; ++k) {
                         for (int j = 0; j < 11; ++j) {
-                            for (int k = 0; k < 11; ++k) {
+                            for (int i = 0; i < 11; ++i) {
                                 for (int comp = 0; comp < numComp; ++comp) {
-                                    double a = 0;
-                                    double b = 0;
-                                    double c = 0;
-                                    a += lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,11,11)];
-                                    c += lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,11,11)];
-                                    a += lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,11,11)];
-                                    c += lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,11,11)];
-                                    a += lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,11,11)];
-                                    c += lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,11,11)];
-                                    a += lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,11,11)];
-                                    c += lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,11,11)];
-                                    a += lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,11,11)];
-                                    c += lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,11,11)];
-                                    a += lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,11,11)];
-                                    c += lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,11,11)];
-                                    a += lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp,11,11)];
-                                    c += lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp,11,11)];
-                                    a += lagrange_deriv_7[i] * e[INDEX4(comp,7,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_7[j] * e[INDEX4(comp,i,7,k,numComp,11,11)];
-                                    c += lagrange_deriv_7[k] * e[INDEX4(comp,i,j,7,numComp,11,11)];
-                                    a += lagrange_deriv_8[i] * e[INDEX4(comp,8,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_8[j] * e[INDEX4(comp,i,8,k,numComp,11,11)];
-                                    c += lagrange_deriv_8[k] * e[INDEX4(comp,i,j,8,numComp,11,11)];
-                                    a += lagrange_deriv_9[i] * e[INDEX4(comp,9,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_9[j] * e[INDEX4(comp,i,9,k,numComp,11,11)];
-                                    c += lagrange_deriv_9[k] * e[INDEX4(comp,i,j,9,numComp,11,11)];
-                                    a += lagrange_deriv_10[i] * e[INDEX4(comp,10,j,k,numComp,11,11)];
-                                    b += lagrange_deriv_10[j] * e[INDEX4(comp,i,10,k,numComp,11,11)];
-                                    c += lagrange_deriv_10[k] * e[INDEX4(comp,i,j,10,numComp,11,11)];
-                                    a *= inv_jac[0];
-                                    grad[INDEX5(0,comp,i,j,k,3,numComp,11,11)] = a;
-                                    b *= inv_jac[1];
-                                    grad[INDEX5(1,comp,i,j,k,3,numComp,11,11)] = b;
-                                    c *= inv_jac[2];
-                                    grad[INDEX5(2,comp,i,j,k,3,numComp,11,11)] = c;
+                                    grad[INDEX5(0,comp,i,j,k,3,numComp,11,11)] = (lagrange_deriv_0[i] * e[INDEX4(comp,0,j,k,numComp,11,11)] + lagrange_deriv_1[i] * e[INDEX4(comp,1,j,k,numComp,11,11)] + lagrange_deriv_2[i] * e[INDEX4(comp,2,j,k,numComp,11,11)] + lagrange_deriv_3[i] * e[INDEX4(comp,3,j,k,numComp,11,11)] + lagrange_deriv_4[i] * e[INDEX4(comp,4,j,k,numComp,11,11)] + lagrange_deriv_5[i] * e[INDEX4(comp,5,j,k,numComp,11,11)] + lagrange_deriv_6[i] * e[INDEX4(comp,6,j,k,numComp, [...]
+                                    grad[INDEX5(1,comp,i,j,k,3,numComp,11,11)] = (lagrange_deriv_0[j] * e[INDEX4(comp,i,0,k,numComp,11,11)] + lagrange_deriv_1[j] * e[INDEX4(comp,i,1,k,numComp,11,11)] + lagrange_deriv_2[j] * e[INDEX4(comp,i,2,k,numComp,11,11)] + lagrange_deriv_3[j] * e[INDEX4(comp,i,3,k,numComp,11,11)] + lagrange_deriv_4[j] * e[INDEX4(comp,i,4,k,numComp,11,11)] + lagrange_deriv_5[j] * e[INDEX4(comp,i,5,k,numComp,11,11)] + lagrange_deriv_6[j] * e[INDEX4(comp,i,6,k,numComp, [...]
+                                    grad[INDEX5(2,comp,i,j,k,3,numComp,11,11)] = (lagrange_deriv_0[k] * e[INDEX4(comp,i,j,0,numComp,11,11)] + lagrange_deriv_1[k] * e[INDEX4(comp,i,j,1,numComp,11,11)] + lagrange_deriv_2[k] * e[INDEX4(comp,i,j,2,numComp,11,11)] + lagrange_deriv_3[k] * e[INDEX4(comp,i,j,3,numComp,11,11)] + lagrange_deriv_4[k] * e[INDEX4(comp,i,j,4,numComp,11,11)] + lagrange_deriv_5[k] * e[INDEX4(comp,i,j,5,numComp,11,11)] + lagrange_deriv_6[k] * e[INDEX4(comp,i,j,6,numComp, [...]
                                 }
                             }
                         }
diff --git a/speckley/src/BrickIntegrals.cpp b/speckley/src/BrickIntegrals.cpp
index ff97c17..7af82ad 100644
--- a/speckley/src/BrickIntegrals.cpp
+++ b/speckley/src/BrickIntegrals.cpp
@@ -1,3 +1,21 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <esysUtils/index.h>
 #include <speckley/Brick.h>
 
diff --git a/speckley/src/BrickIntegrals.cpp b/speckley/src/BrickReductions.cpp
similarity index 56%
copy from speckley/src/BrickIntegrals.cpp
copy to speckley/src/BrickReductions.cpp
index ff97c17..7aa3e28 100644
--- a/speckley/src/BrickIntegrals.cpp
+++ b/speckley/src/BrickReductions.cpp
@@ -1,248 +1,236 @@
-#include <esysUtils/index.h>
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
 #include <speckley/Brick.h>
 
 namespace speckley {
-void Brick::integral_order2(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order2(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.333333333333, 1.33333333333, 0.333333333333};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 3; ++i) {
                         for (int j = 0; j < 3; ++j) {
                             for (int k = 0; k < 3; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,3,3)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,3,3)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order3(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order3(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.166666666667, 0.833333333333, 0.833333333333, 0.166666666667};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 4; ++i) {
                         for (int j = 0; j < 4; ++j) {
                             for (int k = 0; k < 4; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,4,4)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,4,4)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order4(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order4(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.1, 0.544444444444, 0.711111111111, 0.544444444444, 0.1};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 5; ++i) {
                         for (int j = 0; j < 5; ++j) {
                             for (int k = 0; k < 5; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,5,5)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,5,5)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order5(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order5(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.0666666666667, 0.378474956298, 0.554858377035, 0.554858377035, 0.378474956298, 0.0666666666667};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 6; ++i) {
                         for (int j = 0; j < 6; ++j) {
                             for (int k = 0; k < 6; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,6,6)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,6,6)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order6(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order6(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.047619047619, 0.276826047362, 0.43174538121, 0.487619047619, 0.43174538121, 0.276826047362, 0.047619047619};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 7; ++i) {
                         for (int j = 0; j < 7; ++j) {
                             for (int k = 0; k < 7; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,7,7)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,7,7)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order7(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order7(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.0357142857143, 0.210704227144, 0.341122692484, 0.412458794659, 0.412458794659, 0.341122692484, 0.210704227144, 0.0357142857143};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 8; ++i) {
                         for (int j = 0; j < 8; ++j) {
                             for (int k = 0; k < 8; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,8,8)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,8,8)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order8(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order8(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.0277777777778, 0.165495361561, 0.2745387125, 0.346428510973, 0.371519274376, 0.346428510973, 0.2745387125, 0.165495361561, 0.0277777777778};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 9; ++i) {
                         for (int j = 0; j < 9; ++j) {
                             for (int k = 0; k < 9; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,9,9)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,9,9)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order9(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order9(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.0222222222222, 0.133305990851, 0.224889342063, 0.29204268368, 0.327539761184, 0.327539761184, 0.29204268368, 0.224889342063, 0.133305990851, 0.0222222222222};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 10; ++i) {
                         for (int j = 0; j < 10; ++j) {
                             for (int k = 0; k < 10; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,10,10)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,10,10)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
-void Brick::integral_order10(std::vector<double>& integrals, const escript::Data& arg) const {
+void Brick::reduction_order10(const escript::Data& in, escript::Data& out) const {
     const double weights[] = {0.0181818181818, 0.109612273267, 0.18716988178, 0.248048104264, 0.286879124779, 0.300217595456, 0.286879124779, 0.248048104264, 0.18716988178, 0.109612273267, 0.0181818181818};
-    const int numComp = arg.getDataPointSize();
-    const double volume_product = 0.125*m_dx[0]*m_dx[1]*m_dx[2];
+    const int numComp = in.getDataPointSize();
     for (int ei = 0; ei < m_NE[2]; ++ei) {
         for (int ej = 0; ej < m_NE[1]; ++ej) {
             for (int ek = 0; ek < m_NE[0]; ++ek) {
-                const double *e = arg.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
-                double result = 0;
+                const double *e_in = in.getSampleDataRO(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
+                double *e_out = out.getSampleDataRW(INDEX3(ek,ej,ei,m_NE[0],m_NE[1]));
                 for (int comp = 0; comp < numComp; ++comp) {
+                    double result = 0;
                     for (int i = 0; i < 11; ++i) {
                         for (int j = 0; j < 11; ++j) {
                             for (int k = 0; k < 11; ++k) {
-                                result += weights[i] * weights[j] * weights[k] * e[INDEX4(comp,i,j,k,numComp,11,11)];
+                                result += weights[i] * weights[j] * weights[k] * e_in[INDEX4(comp,k,j,i,numComp,11,11)];
                             }
                         }
                     }
-                    integrals[comp] += result;
+                    e_out[comp] += result / 8.;
                 }
             }
         }
     }
-    for (int comp = 0; comp < numComp; ++comp) {
-        integrals[comp] *= volume_product;
-    }
 }
 
 }
diff --git a/speckley/src/CrossDomainCoupler.cpp b/speckley/src/CrossDomainCoupler.cpp
index 6bf2d6a..aaae9f2 100644
--- a/speckley/src/CrossDomainCoupler.cpp
+++ b/speckley/src/CrossDomainCoupler.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,6 +13,11 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/CrossDomainCoupler.h>
 
 #include <speckley/lagrange_functions.h>
diff --git a/speckley/src/CrossDomainCoupler.h b/speckley/src/CrossDomainCoupler.h
index b9ac749..5ef44c1 100644
--- a/speckley/src/CrossDomainCoupler.h
+++ b/speckley/src/CrossDomainCoupler.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/DefaultAssembler2D.cpp b/speckley/src/DefaultAssembler2D.cpp
index 37cb07c..16b75e4 100644
--- a/speckley/src/DefaultAssembler2D.cpp
+++ b/speckley/src/DefaultAssembler2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,6 +13,11 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/DefaultAssembler2D.h>
 #include <speckley/domainhelpers.h>
 #include <esysUtils/index.h>
diff --git a/speckley/src/DefaultAssembler2D.h b/speckley/src/DefaultAssembler2D.h
index 5bec1d6..5e28080 100644
--- a/speckley/src/DefaultAssembler2D.h
+++ b/speckley/src/DefaultAssembler2D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/DefaultAssembler3D.cpp b/speckley/src/DefaultAssembler3D.cpp
index 942f808..2582bf9 100644
--- a/speckley/src/DefaultAssembler3D.cpp
+++ b/speckley/src/DefaultAssembler3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,6 +13,11 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/DefaultAssembler3D.h>
 #include <speckley/domainhelpers.h>
 #include <esysUtils/index.h>
diff --git a/speckley/src/DefaultAssembler3D.h b/speckley/src/DefaultAssembler3D.h
index b3d7aae..202fe96 100644
--- a/speckley/src/DefaultAssembler3D.h
+++ b/speckley/src/DefaultAssembler3D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/Rectangle.cpp b/speckley/src/Rectangle.cpp
index a4afa0b..eef9549 100644
--- a/speckley/src/Rectangle.cpp
+++ b/speckley/src/Rectangle.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+#include <boost/math/special_functions/fpclassify.hpp> // for isnan
 #include <algorithm>
 #include <limits>
 
@@ -22,6 +26,7 @@
 #include <esysUtils/index.h>
 #include <esysUtils/Esys_MPI.h>
 #include <speckley/DefaultAssembler2D.h>
+#include <speckley/WaveAssembler2D.h>
 #include <boost/scoped_array.hpp>
 #include <escript/FunctionSpaceFactory.h>
 #include "esysUtils/EsysRandom.h"
@@ -43,8 +48,9 @@
 
 #include <iomanip>
 
+namespace bm=boost::math;
 using esysUtils::FileWriter;
-using namespace std;	// to allow isnan to work
+
 namespace speckley {
 
 Rectangle::Rectangle(int order, dim_t n0, dim_t n1, double x0, double y0, double x1,
@@ -299,7 +305,7 @@ void Rectangle::readNcGrid(escript::Data& out, std::string filename,
             const dim_t baseIndex = first0+x*params.multiplier[0]
                                   +(first1+y*params.multiplier[1])*myN0;
             const dim_t srcIndex = (y0+y_mult*y)*num0+(x0+x_mult*x);
-            if (!isnan(values[srcIndex])) {
+            if (!bm::isnan(values[srcIndex])) {
                 for (index_t m1=0; m1<params.multiplier[1]; m1++) {
                     for (index_t m0=0; m0<params.multiplier[0]; m0++) {
                         const dim_t dataIndex = baseIndex+m0+m1*myN0;
@@ -467,7 +473,7 @@ void Rectangle::readBinaryGridImpl(escript::Data& out, const std::string& filena
                                 byte_swap32(cval);
                             }
                         }
-                        if (!isnan(val)) {
+                        if (!bm::isnan(val)) {
                             for (int q=0; q<dpp; q++) {
                                 *dest++ = static_cast<double>(val);
                             }
@@ -581,7 +587,7 @@ void Rectangle::readBinaryGridZippedImpl(escript::Data& out, const std::string&
                                 byte_swap32(cval);
                             }
                         }
-                        if (!isnan(val)) {
+                        if (!bm::isnan(val)) {
                             for (int q=0; q<dpp; q++) {
                                 *dest++ = static_cast<double>(val);
                             }
@@ -869,6 +875,7 @@ const dim_t* Rectangle::borrowSampleReferenceIDs(int fsType) const
         case Nodes:
             return &m_nodeId[0];
         case Elements:
+        case ReducedElements:
             return &m_elementId[0];
         case Points:
             return &m_diracPointNodeIDs[0];
@@ -895,13 +902,33 @@ void Rectangle::setToSize(escript::Data& out) const
 {
     if (out.getFunctionSpace().getTypeCode() == Elements) {
         out.requireWrite();
-        const dim_t numQuad = out.getNumDataPointsPerSample();
+        const dim_t numQuad = m_order + 1;
         const dim_t numElements = getNumElements();
-        const double size=sqrt(m_dx[0]*m_dx[0]+m_dx[1]*m_dx[1]);
+        const double *quad_locs = point_locations[m_order-2];
+        //since elements are uniform, calc the first and copy to others
+        double* first_element = out.getSampleDataRW(0);
+#pragma omp parallel for
+        for (short qy = 0; qy < m_order; qy++) {
+            const double y = quad_locs[qy+1] - quad_locs[qy];
+            for (short qx = 0; qx < m_order; qx++) {
+                const double x = quad_locs[qx+1] - quad_locs[qx];
+                first_element[qx + qy*numQuad] = sqrt(x*x + y*y);
+            }
+        }
+        const short top_start = (numQuad - 1)*numQuad;
+        for (short edge = 0; edge < m_order; edge++) {
+            //right edge = left edge
+            first_element[(edge+1)*numQuad - 1] = first_element[edge*numQuad];
+            //top edge = bottom edge
+            first_element[top_start + edge] = first_element[edge];
+        }
+        //top-right corner
+        first_element[numQuad*numQuad - 1] = first_element[0];
+        const size_t size = numQuad*numQuad*sizeof(double);
 #pragma omp parallel for
         for (index_t k = 0; k < numElements; ++k) {
             double* o = out.getSampleDataRW(k);
-            std::fill(o, o+numQuad, size);
+            memcpy(o, first_element, size);
         }
     } else {
         std::stringstream msg;
@@ -930,11 +957,10 @@ void Rectangle::Print_Mesh_Info(const bool full) const
 //protected
 void Rectangle::assembleCoordinates(escript::Data& arg) const
 {
-    escriptDataC x = arg.getDataC();
     int numDim = m_numDim;
-    if (!isDataPointShapeEqual(&x, 1, &numDim))
+    if (&arg!=0 && !arg.isDataPointShapeEqual(1, &numDim))
         throw SpeckleyException("setToX: Invalid Data object shape");
-    if (!numSamplesEqual(&x, 1, getNumNodes()))
+    if (&arg!=0 && !arg.numSamplesEqual(1, getNumNodes()))
         throw SpeckleyException("setToX: Illegal number of samples in Data object");
 
     const dim_t NN0 = m_NN[0];
@@ -1142,9 +1168,33 @@ void Rectangle::addToMatrixAndRHS(escript::AbstractSystemMatrix* S, escript::Dat
     throw SpeckleyException("Rectangle::addToMatrixAndRHS, adding to matrix not supported");
 }
 
+void Rectangle::reduceElements(escript::Data& out, const escript::Data& in) const
+{
+    if (m_order == 2) {
+        reduction_order2(in, out);
+    } else if (m_order == 3) {
+        reduction_order3(in, out);
+    } else if (m_order == 4) {
+        reduction_order4(in, out);
+    } else if (m_order == 5) {
+        reduction_order5(in, out);
+    } else if (m_order == 6) {
+        reduction_order6(in, out);
+    } else if (m_order == 7) {
+        reduction_order7(in, out);
+    } else if (m_order == 8) {
+        reduction_order8(in, out);
+    } else if (m_order == 9) {
+        reduction_order9(in, out);
+    } else if (m_order == 10) {
+        reduction_order10(in, out);
+    }
+}
+
 //protected
 void Rectangle::interpolateNodesOnElements(escript::Data& out,
-                                           const escript::Data& in) const
+                                           const escript::Data& in,
+                                           bool reduced) const
 {
     const dim_t numComp = in.getDataPointSize();
     const dim_t NE0 = m_NE[0];
@@ -1152,6 +1202,11 @@ void Rectangle::interpolateNodesOnElements(escript::Data& out,
     const int quads = m_order + 1;
     const int max_x = m_NN[0];
     out.requireWrite();
+    if (reduced) { //going to ReducedElements
+        escript::Data funcIn(in, escript::function(*this));
+        reduceElements(out, funcIn);
+        return;
+    }
 #pragma omp parallel for
     for (dim_t ey = 0; ey < NE1; ey++) {
         for (dim_t ex = 0; ex < NE0; ex++) {
@@ -1273,18 +1328,39 @@ void Rectangle::interpolateElementsOnNodes(escript::Data& out,
     const dim_t max_x = (m_order*NE0) + 1;
     const dim_t max_y = (m_order*NE1) + 1;
     out.requireWrite();
+    const int inFS = in.getFunctionSpace().getTypeCode();
     // the summation portion
-    for (dim_t colouring = 0; colouring < 2; colouring++) {
+    if (inFS == ReducedElements) {
+        for (dim_t colouring = 0; colouring < 2; colouring++) {
 #pragma omp parallel for
-        for (dim_t ey = colouring; ey < NE1; ey += 2) {
-            for (dim_t ex = 0; ex < NE0; ex++) {
-                dim_t start = ex*m_order + ey*max_x*m_order;
-                const double *e_in = in.getSampleDataRO(ex + ey*NE0);
-                for (int qy = 0; qy < quads; qy++) {
-                    for (int qx = 0; qx < quads; qx++) {
-                        double *n_out = out.getSampleDataRW(start + max_x*qy + qx);
-                        for (int comp = 0; comp < numComp; comp++) {
-                            n_out[comp] += e_in[INDEX3(comp, qx, qy, numComp, quads)];
+            for (dim_t ey = colouring; ey < NE1; ey += 2) {
+                for (dim_t ex = 0; ex < NE0; ex++) {
+                    dim_t start = ex*m_order + ey*max_x*m_order;
+                    const double *e_in = in.getSampleDataRO(ex + ey*NE0);
+                    for (int qy = 0; qy < quads; qy++) {
+                        for (int qx = 0; qx < quads; qx++) {
+                            double *n_out = out.getSampleDataRW(start + max_x*qy + qx);
+                            for (int comp = 0; comp < numComp; comp++) {
+                                n_out[comp] += e_in[comp];
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    } else { //inFS == Elements
+        for (dim_t colouring = 0; colouring < 2; colouring++) {
+#pragma omp parallel for
+            for (dim_t ey = colouring; ey < NE1; ey += 2) {
+                for (dim_t ex = 0; ex < NE0; ex++) {
+                    dim_t start = ex*m_order + ey*max_x*m_order;
+                    const double *e_in = in.getSampleDataRO(ex + ey*NE0);
+                    for (int qy = 0; qy < quads; qy++) {
+                        for (int qx = 0; qx < quads; qx++) {
+                            double *n_out = out.getSampleDataRW(start + max_x*qy + qx);
+                            for (int comp = 0; comp < numComp; comp++) {
+                                n_out[comp] += e_in[INDEX3(comp, qx, qy, numComp, quads)];
+                            }
                         }
                     }
                 }
@@ -1326,16 +1402,21 @@ void Rectangle::shareCorners(escript::Data& out, int rx, int ry) const
     //setup
     const int tag = 0;
     MPI_Status status;
+    MPI_Request request[4];
     const int numComp = out.getDataPointSize();
     const int count = 4 * numComp;
     std::vector<double> outbuf(count, 0);
     std::vector<double> inbuf(count, 0);
     const int rank = m_mpiInfo->rank;
     //precalc bounds so we can loop nicely, can probably be cleaned up
-    const bool conds[4] = {rx && ry, rx < (m_NX[0] - 1) && ry,
-            rx && ry < (m_NX[1] - 1),rx < (m_NX[0] - 1) && ry < (m_NX[1] - 1)};
-    const int ranks[4] = {rank-m_NX[0]-1,rank-m_NX[0]+1,
-                        rank+m_NX[0]-1,rank+m_NX[0]+1};
+    const bool conds[4] = {rx && ry,
+                           rx < (m_NX[0] - 1) && ry,
+                           rx && ry < (m_NX[1] - 1),
+                           rx < (m_NX[0] - 1) && ry < (m_NX[1] - 1)};
+    const int ranks[4] = {rank-m_NX[0]-1,
+                          rank-m_NX[0]+1,
+                          rank+m_NX[0]-1,
+                          rank+m_NX[0]+1};
     //fill everything, regardless of whether we're sharing that corner or not
     for (int y = 0; y < 2; y++) {
         for (int x = 0; x < 2; x++) {
@@ -1347,21 +1428,30 @@ void Rectangle::shareCorners(escript::Data& out, int rx, int ry) const
     //share
     for (int i = 0; i < 4; i++) {
         if (conds[i]) {
-            MPI_Sendrecv(&outbuf[i], numComp, MPI_DOUBLE, ranks[i], tag,
-                    &inbuf[i], count, MPI_DOUBLE, ranks[i], tag,
-                    m_mpiInfo->comm, &status);
+            MPI_Isend(&outbuf[i], numComp, MPI_DOUBLE, ranks[i], tag,
+                    m_mpiInfo->comm, &request[i]);
         }
     }
 
     //unpack
     for (int y = 0; y < 2; y++) {
         for (int x = 0; x < 2; x++) {
-            double *data = out.getSampleDataRW(x*(m_NN[0]-1) + y*(m_NN[1]-1)*m_NN[0]);
-            for (int comp = 0; comp < numComp; comp++) {
-                data[comp] += inbuf[(x + 2*y)*numComp + comp];
+            int i = 2*y+x;
+            if (conds[i]) {
+                MPI_Recv(&inbuf[i], numComp, MPI_DOUBLE, ranks[i], tag,
+                        m_mpiInfo->comm, &status);
+                double *data = out.getSampleDataRW(x*(m_NN[0]-1) + y*(m_NN[1]-1)*m_NN[0]);
+                for (int comp = 0; comp < numComp; comp++) {
+                    data[comp] += inbuf[i*numComp + comp];
+                }
             }
         }
     }
+    for (int i = 0; i < 4; i++) {
+        if (conds[i]) {
+            MPI_Wait(request + i, &status);
+        }
+    }
 }
 
 //private
@@ -1379,52 +1469,46 @@ void Rectangle::shareVertical(escript::Data& out, int rx, int ry) const
     double *top = out.getSampleDataRW((m_NN[1]-1) * m_NN[0]);
     double *bottom = out.getSampleDataRW(0);
 
-    if (ry % 2) {
-        //send to up, read from up
-        if (ry < m_NX[1] - 1) {
-            MPI_Send(&top[0], count, MPI_DOUBLE, up_neighbour, tag,
-                    m_mpiInfo->comm);
-            MPI_Recv(&recv[0], count, MPI_DOUBLE, up_neighbour, tag,
-                    m_mpiInfo->comm, &status);
-            //unpack up
-            for (dim_t i = 0; i < count; i++) {
-                top[i] += recv[i];
-            }
-        }
-        //send down, read down
-        MPI_Send(&bottom[0], count, MPI_DOUBLE, down_neighbour, tag,
-                    m_mpiInfo->comm);
+    MPI_Request request[2];
+    
+    if (ry) {
+        MPI_Isend(bottom, count, MPI_DOUBLE, down_neighbour, tag,
+                m_mpiInfo->comm, request);
+    }
+
+    if (ry < m_NX[1] - 1) {
+        MPI_Isend(top, count, MPI_DOUBLE, up_neighbour, tag,
+            m_mpiInfo->comm, request+1);
+    }
+    
+    //read down
+    if (ry) {
         MPI_Recv(&recv[0], count, MPI_DOUBLE, down_neighbour, tag,
-                    m_mpiInfo->comm, &status);
+                m_mpiInfo->comm, &status);
+
         //unpack bottom
         for (dim_t i = 0; i < count; i++) {
             bottom[i] += recv[i];
         }
-    } else {
-        //read down, send down
-        if (ry) {
-            MPI_Recv(&recv[0], count, MPI_DOUBLE, down_neighbour, tag,
-                    m_mpiInfo->comm, &status);
-            MPI_Send(&bottom[0], count, MPI_DOUBLE, down_neighbour, tag,
-                    m_mpiInfo->comm);
-            //unpack bottom
-            for (dim_t i = 0; i < count; i++) {
-                bottom[i] += recv[i];
-            }
-        }
+    }
 
-        //read up, send up
-        if (ry < m_NX[1] - 1) {
-            MPI_Recv(&recv[0], count, MPI_DOUBLE, up_neighbour, tag,
-                    m_mpiInfo->comm, &status);
-            MPI_Send(&top[0], count, MPI_DOUBLE, up_neighbour, tag,
-                    m_mpiInfo->comm);
-            //unpack up
-            for (dim_t i = 0; i < count; i++) {
-                top[i] += recv[i];
-            }
+    //read up, send up
+    if (ry < m_NX[1] - 1) {
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, up_neighbour, tag,
+                m_mpiInfo->comm, &status);
+
+        //unpack up
+        for (dim_t i = 0; i < count; i++) {
+            top[i] += recv[i];
         }
     }
+    
+    if (ry) {
+        MPI_Wait(request, &status);
+    }
+    if (ry < m_NX[1] - 1) {
+        MPI_Wait(request+1, &status);
+    }
 }
 
 //private
@@ -1440,35 +1524,33 @@ void Rectangle::shareSides(escript::Data& out, int rx, int ry) const
     std::vector<double> left(count,170);
     std::vector<double> right(count,17000);
     std::vector<double> recv(count,1700);
-    //fill those values
-    for (dim_t n = 0; n < m_NN[1]; n++) {
-        index_t index = n*m_NN[0];
-        const double *leftData = out.getSampleDataRO(index);
-        std::copy(leftData, leftData + numComp, &left[n*numComp]);
-        const double *rightData = out.getSampleDataRO(index+m_NN[0]-1);
-        std::copy(rightData, rightData + numComp, &right[n*numComp]);
-    }
-
-    if (rx % 2) {
-        //send to right, read from right
-        if (rx < m_NX[0] - 1) {
-            MPI_Send(&right[0], count, MPI_DOUBLE, right_neighbour, tag,
-                    m_mpiInfo->comm);
-            MPI_Recv(&recv[0], count, MPI_DOUBLE, right_neighbour, tag,
-                    m_mpiInfo->comm, &status);
-            //unpack to right
-            for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW((i + 1) * m_NN[0] - 1);
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += recv[i*numComp+comp];
-                }
-            }
+
+    MPI_Request request[2];
+
+    if (rx) {
+        for (dim_t n = 0; n < m_NN[1]; n++) {
+            index_t index = n*m_NN[0];
+            const double *leftData = out.getSampleDataRO(index);
+            std::copy(leftData, leftData + numComp, &left[n*numComp]);
         }
-        //send left, read left
-        MPI_Send(&left[0], count, MPI_DOUBLE, left_neighbour, tag,
-                    m_mpiInfo->comm);
+        MPI_Isend(&left[0], count, MPI_DOUBLE, left_neighbour, tag,
+                m_mpiInfo->comm, request);
+    }
+
+    if (rx < m_NX[0] - 1) {
+        for (dim_t n = 0; n < m_NN[1]; n++) {
+            index_t index = n*m_NN[0];
+            const double *rightData = out.getSampleDataRO(index+m_NN[0]-1);
+            std::copy(rightData, rightData + numComp, &right[n*numComp]);
+        }
+        MPI_Isend(&right[0], count, MPI_DOUBLE, right_neighbour, tag,
+                m_mpiInfo->comm, request+1);
+    }
+
+    //read left
+    if (rx) {
         MPI_Recv(&recv[0], count, MPI_DOUBLE, left_neighbour, tag,
-                    m_mpiInfo->comm, &status);
+                m_mpiInfo->comm, &status);
         //unpack to left
         for (dim_t i = 0; i < m_NN[1]; i++) {
             double *data = out.getSampleDataRW(i*m_NN[0]);
@@ -1476,37 +1558,26 @@ void Rectangle::shareSides(escript::Data& out, int rx, int ry) const
                 data[comp] += recv[i*numComp+comp];
             }
         }
-    } else {
-        //read left, send left
-        if (rx) {
-            MPI_Recv(&recv[0], count, MPI_DOUBLE, left_neighbour, tag,
-                    m_mpiInfo->comm, &status);
-            MPI_Send(&left[0], count, MPI_DOUBLE, left_neighbour, tag,
-                    m_mpiInfo->comm);
-            //unpack to left
-            for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW(i*m_NN[0]);
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += recv[i*numComp+comp];
-                }
-            }
-        }
+    }
 
-        //read right, send right
-        if (rx < m_NX[0] - 1) {
-            MPI_Recv(&recv[0], count, MPI_DOUBLE, right_neighbour, tag,
-                    m_mpiInfo->comm, &status);
-            MPI_Send(&right[0], count, MPI_DOUBLE, right_neighbour, tag,
-                    m_mpiInfo->comm);
-            //unpack to right
-            for (dim_t i = 0; i < m_NN[1]; i++) {
-                double *data = out.getSampleDataRW((i + 1) * m_NN[0] - 1);
-                for (int comp = 0; comp < numComp; comp++) {
-                    data[comp] += recv[i*numComp+comp];
-                }
+    //read right
+    if (rx < m_NX[0] - 1) {
+        MPI_Recv(&recv[0], count, MPI_DOUBLE, right_neighbour, tag,
+                m_mpiInfo->comm, &status);
+        //unpack to right
+        for (dim_t i = 0; i < m_NN[1]; i++) {
+            double *data = out.getSampleDataRW((i + 1) * m_NN[0] - 1);
+            for (int comp = 0; comp < numComp; comp++) {
+                data[comp] += recv[i*numComp+comp];
             }
         }
     }
+    if (rx) {
+        MPI_Wait(request, &status);
+    }
+    if (rx < m_NX[0] - 1) {
+        MPI_Wait(request+1, &status);
+    }
 }
 #endif //#ifdef ESYS_MPI
 
@@ -1565,9 +1636,12 @@ dim_t Rectangle::findNode(const double *coords) const
 }
 
 Assembler_ptr Rectangle::createAssembler(std::string type,
-        const DataMap& options) const {
+        const DataMap& options) const
+{
     if (type.compare("DefaultAssembler") == 0) {
         return Assembler_ptr(new DefaultAssembler2D(shared_from_this(), m_dx, m_NE, m_NN));
+    } else if (type.compare("WaveAssembler") == 0) {
+        return Assembler_ptr(new WaveAssembler2D(shared_from_this(), m_dx, m_NE, m_NN, options));
     }
     throw SpeckleyException("Speckley::Rectangle does not support the"
             " requested assembler");
diff --git a/speckley/src/Rectangle.h b/speckley/src/Rectangle.h
index 58a6e26..3c47e3c 100644
--- a/speckley/src/Rectangle.h
+++ b/speckley/src/Rectangle.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -233,10 +233,12 @@ protected:
     virtual void assembleIntegrate(DoubleVector& integrals,
                                    const escript::Data& arg) const;
     virtual void interpolateNodesOnElements(escript::Data& out,
-                                  const escript::Data& in) const;
+                                  const escript::Data& in,
+                                  bool reduced) const;
     virtual void interpolateElementsOnNodes(escript::Data& out,
                                 const escript::Data& in) const;
     virtual dim_t getDofOfNode(dim_t node) const;
+    virtual void reduceElements(escript::Data& out, const escript::Data& in) const;
 
 private:
     void gradient_order2(escript::Data&, const escript::Data&) const;
@@ -249,6 +251,16 @@ private:
     void gradient_order9(escript::Data&, const escript::Data&) const;
     void gradient_order10(escript::Data&, const escript::Data&) const;
 
+    void reduction_order2(const escript::Data&, escript::Data&) const;
+    void reduction_order3(const escript::Data&, escript::Data&) const;
+    void reduction_order4(const escript::Data&, escript::Data&) const;
+    void reduction_order5(const escript::Data&, escript::Data&) const;
+    void reduction_order6(const escript::Data&, escript::Data&) const;
+    void reduction_order7(const escript::Data&, escript::Data&) const;
+    void reduction_order8(const escript::Data&, escript::Data&) const;
+    void reduction_order9(const escript::Data&, escript::Data&) const;
+    void reduction_order10(const escript::Data&, escript::Data&) const;
+
     void integral_order2(std::vector<double>&, const escript::Data&) const;
     void integral_order3(std::vector<double>&, const escript::Data&) const;
     void integral_order4(std::vector<double>&, const escript::Data&) const;
@@ -339,6 +351,7 @@ private:
 #endif
 
     friend class DefaultAssembler2D;
+    friend class WaveAssembler2D;
 };
 
 ////////////////////////////// inline methods ////////////////////////////////
diff --git a/speckley/src/RectangleGradients.cpp b/speckley/src/RectangleGradients.cpp
index a9a5d3c..fba0910 100644
--- a/speckley/src/RectangleGradients.cpp
+++ b/speckley/src/RectangleGradients.cpp
@@ -1,3 +1,21 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
 #include <esysUtils/index.h>
 #include <speckley/Rectangle.h>
 
@@ -16,20 +34,13 @@ void Rectangle::gradient_order2(escript::Data& out, const escript::Data& in) con
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp]) * inv_jac[1];
                     for (int j = 0; j < 3; ++j) {
                         for (int i = 0; i < 3; ++i) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,3)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,3)] = b;
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,3);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -44,18 +55,8 @@ void Rectangle::gradient_order2(escript::Data& out, const escript::Data& in) con
                 for (int j = 0; j < 3; ++j) {
                     for (int i = 0; i < 3; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,3)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,3)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,3)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,3)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,3)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,3)];
-                            a *= inv_jac[0];
-                            b *= inv_jac[1];
-                            grad[INDEX4(0,comp,i,j,2,numComp,3)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,3)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,3)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,3)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,3)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,3)]) * inv_jac[0];
+                            grad[INDEX4(1,comp,i,j,2,numComp,3)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,3)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,3)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,3)]) * inv_jac[1];
                         }
                     }
                 }
@@ -79,22 +80,13 @@ void Rectangle::gradient_order3(escript::Data& out, const escript::Data& in) con
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp]) * inv_jac[1];
                     for (int j = 0; j < 4; ++j) {
                         for (int i = 0; i < 4; ++i) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,4)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,4)] = b;
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,4);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -109,20 +101,8 @@ void Rectangle::gradient_order3(escript::Data& out, const escript::Data& in) con
                 for (int j = 0; j < 4; ++j) {
                     for (int i = 0; i < 4; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,4)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,4)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,4)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,4)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,4)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,4)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,4)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,4)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,4)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,4)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,4)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,4)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,4)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,4)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,4)]) * inv_jac[0];
+                            grad[INDEX4(1,comp,i,j,2,numComp,4)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,4)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,4)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,4)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,4)]) * inv_jac[1];
                         }
                     }
                 }
@@ -141,32 +121,19 @@ void Rectangle::gradient_order4(escript::Data& out, const escript::Data& in) con
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 25 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 5; ++i) {
-                        for (int j = 0; j < 5; ++j) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,5)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,5)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 5; ++j) {
+                        for (int i = 0; i < 5; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,5);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -176,28 +143,13 @@ void Rectangle::gradient_order4(escript::Data& out, const escript::Data& in) con
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
-                int e_index = INDEX2(ej,ei,m_NE[0]);
-                const double *e = in.getSampleDataRO(e_index);
-                double *grad = out.getSampleDataRW(e_index);
-                for (int i = 0; i < 5; ++i) {
-                    for (int j = 0; j < 5; ++j) {
+                const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+                double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+                for (int j = 0; j < 5; ++j) {
+                    for (int i = 0; i < 5; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,5)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,5)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,5)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,5)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,5)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,5)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,5)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,5)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,5)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,5)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,5)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,5)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,5)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,5)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,5)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,5)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,5)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,5)]) * inv_jac[0];
+                            grad[INDEX4(1,comp,i,j,2,numComp,5)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,5)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,5)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,5)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,5)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,5)]) * inv_jac[1];
                         }
                     }
                 }
@@ -217,34 +169,19 @@ void Rectangle::gradient_order5(escript::Data& out, const escript::Data& in) con
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 36 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a += lagrange_deriv_5[0] * e[comp];
-                    b += lagrange_deriv_5[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 6; ++i) {
-                        for (int j = 0; j < 6; ++j) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,6)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,6)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 6; ++j) {
+                        for (int i = 0; i < 6; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,6);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -256,27 +193,11 @@ void Rectangle::gradient_order5(escript::Data& out, const escript::Data& in) con
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
-                for (int i = 0; i < 6; ++i) {
-                    for (int j = 0; j < 6; ++j) {
+                for (int j = 0; j < 6; ++j) {
+                    for (int i = 0; i < 6; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,6)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,6)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,6)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,6)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,6)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,6)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,6)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,6)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,6)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,6)];
-                            a += lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,6)];
-                            b += lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,6)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,6)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,6)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,6)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,6)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,6)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,6)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,6)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,6)] + lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,6)]) * inv_jac[0];
+                            grad[INDEX4(1,comp,i,j,2,numComp,6)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,6)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,6)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,6)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,6)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,6)] + lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,6)]) * inv_jac[1];
                         }
                     }
                 }
@@ -297,36 +218,19 @@ void Rectangle::gradient_order6(escript::Data& out, const escript::Data& in) con
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 49 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a += lagrange_deriv_5[0] * e[comp];
-                    b += lagrange_deriv_5[0] * e[comp];
-                    a += lagrange_deriv_6[0] * e[comp];
-                    b += lagrange_deriv_6[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 7; ++i) {
-                        for (int j = 0; j < 7; ++j) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,7)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,7)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 7; ++j) {
+                        for (int i = 0; i < 7; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,7);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -338,29 +242,11 @@ void Rectangle::gradient_order6(escript::Data& out, const escript::Data& in) con
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
-                for (int i = 0; i < 7; ++i) {
-                    for (int j = 0; j < 7; ++j) {
+                for (int j = 0; j < 7; ++j) {
+                    for (int i = 0; i < 7; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,7)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,7)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,7)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,7)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,7)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,7)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,7)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,7)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,7)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,7)];
-                            a += lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,7)];
-                            b += lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,7)];
-                            a += lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,7)];
-                            b += lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,7)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,7)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,7)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,7)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,7)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,7)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,7)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,7)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,7)] + lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,7)] + lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,7)]) * inv_jac[0];
+                            grad[INDEX4(1,comp,i,j,2,numComp,7)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,7)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,7)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,7)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,7)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,7)] + lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,7)] + lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,7)]) * inv_jac[1];
                         }
                     }
                 }
@@ -382,38 +268,19 @@ void Rectangle::gradient_order7(escript::Data& out, const escript::Data& in) con
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 64 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a += lagrange_deriv_5[0] * e[comp];
-                    b += lagrange_deriv_5[0] * e[comp];
-                    a += lagrange_deriv_6[0] * e[comp];
-                    b += lagrange_deriv_6[0] * e[comp];
-                    a += lagrange_deriv_7[0] * e[comp];
-                    b += lagrange_deriv_7[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 8; ++i) {
-                        for (int j = 0; j < 8; ++j) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,8)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,8)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 8; ++j) {
+                        for (int i = 0; i < 8; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,8);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -425,31 +292,11 @@ void Rectangle::gradient_order7(escript::Data& out, const escript::Data& in) con
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
-                for (int i = 0; i < 8; ++i) {
-                    for (int j = 0; j < 8; ++j) {
+                for (int j = 0; j < 8; ++j) {
+                    for (int i = 0; i < 8; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,8)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,8)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,8)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,8)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,8)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,8)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,8)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,8)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,8)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,8)];
-                            a += lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,8)];
-                            b += lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,8)];
-                            a += lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,8)];
-                            b += lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,8)];
-                            a += lagrange_deriv_7[i] * e[INDEX3(comp,7,j,numComp,8)];
-                            b += lagrange_deriv_7[j] * e[INDEX3(comp,i,7,numComp,8)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,8)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,8)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,8)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,8)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,8)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,8)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,8)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,8)] + lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,8)] + lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,8)] + lagrange_deriv_7[i] * e[INDEX3(comp,7,j,numCom [...]
+                            grad[INDEX4(1,comp,i,j,2,numComp,8)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,8)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,8)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,8)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,8)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,8)] + lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,8)] + lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,8)] + lagrange_deriv_7[j] * e[INDEX3(comp,i,7,numCom [...]
                         }
                     }
                 }
@@ -472,40 +319,19 @@ void Rectangle::gradient_order8(escript::Data& out, const escript::Data& in) con
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 81 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a += lagrange_deriv_5[0] * e[comp];
-                    b += lagrange_deriv_5[0] * e[comp];
-                    a += lagrange_deriv_6[0] * e[comp];
-                    b += lagrange_deriv_6[0] * e[comp];
-                    a += lagrange_deriv_7[0] * e[comp];
-                    b += lagrange_deriv_7[0] * e[comp];
-                    a += lagrange_deriv_8[0] * e[comp];
-                    b += lagrange_deriv_8[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 9; ++i) {
-                        for (int j = 0; j < 9; ++j) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,9)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,9)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 9; ++j) {
+                        for (int i = 0; i < 9; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,9);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -517,33 +343,11 @@ void Rectangle::gradient_order8(escript::Data& out, const escript::Data& in) con
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
-                for (int i = 0; i < 9; ++i) {
-                    for (int j = 0; j < 9; ++j) {
+                for (int j = 0; j < 9; ++j) {
+                    for (int i = 0; i < 9; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,9)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,9)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,9)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,9)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,9)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,9)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,9)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,9)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,9)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,9)];
-                            a += lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,9)];
-                            b += lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,9)];
-                            a += lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,9)];
-                            b += lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,9)];
-                            a += lagrange_deriv_7[i] * e[INDEX3(comp,7,j,numComp,9)];
-                            b += lagrange_deriv_7[j] * e[INDEX3(comp,i,7,numComp,9)];
-                            a += lagrange_deriv_8[i] * e[INDEX3(comp,8,j,numComp,9)];
-                            b += lagrange_deriv_8[j] * e[INDEX3(comp,i,8,numComp,9)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,9)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,9)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,9)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,9)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,9)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,9)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,9)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,9)] + lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,9)] + lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,9)] + lagrange_deriv_7[i] * e[INDEX3(comp,7,j,numCom [...]
+                            grad[INDEX4(1,comp,i,j,2,numComp,9)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,9)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,9)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,9)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,9)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,9)] + lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,9)] + lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,9)] + lagrange_deriv_7[j] * e[INDEX3(comp,i,7,numCom [...]
                         }
                     }
                 }
@@ -567,42 +371,19 @@ void Rectangle::gradient_order9(escript::Data& out, const escript::Data& in) con
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 100 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a += lagrange_deriv_5[0] * e[comp];
-                    b += lagrange_deriv_5[0] * e[comp];
-                    a += lagrange_deriv_6[0] * e[comp];
-                    b += lagrange_deriv_6[0] * e[comp];
-                    a += lagrange_deriv_7[0] * e[comp];
-                    b += lagrange_deriv_7[0] * e[comp];
-                    a += lagrange_deriv_8[0] * e[comp];
-                    b += lagrange_deriv_8[0] * e[comp];
-                    a += lagrange_deriv_9[0] * e[comp];
-                    b += lagrange_deriv_9[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 10; ++i) {
-                        for (int j = 0; j < 10; ++j) {
-                            grad[INDEX4(0,comp,i,j,2,numComp,10)] = a;
-                            grad[INDEX4(1,comp,i,j,2,numComp,10)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 10; ++j) {
+                        for (int i = 0; i < 10; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,10);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -614,35 +395,11 @@ void Rectangle::gradient_order9(escript::Data& out, const escript::Data& in) con
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
-                for (int i = 0; i < 10; ++i) {
-                    for (int j = 0; j < 10; ++j) {
+                for (int j = 0; j < 10; ++j) {
+                    for (int i = 0; i < 10; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,10)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,10)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,10)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,10)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,10)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,10)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,10)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,10)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,10)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,10)];
-                            a += lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,10)];
-                            b += lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,10)];
-                            a += lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,10)];
-                            b += lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,10)];
-                            a += lagrange_deriv_7[i] * e[INDEX3(comp,7,j,numComp,10)];
-                            b += lagrange_deriv_7[j] * e[INDEX3(comp,i,7,numComp,10)];
-                            a += lagrange_deriv_8[i] * e[INDEX3(comp,8,j,numComp,10)];
-                            b += lagrange_deriv_8[j] * e[INDEX3(comp,i,8,numComp,10)];
-                            a += lagrange_deriv_9[i] * e[INDEX3(comp,9,j,numComp,10)];
-                            b += lagrange_deriv_9[j] * e[INDEX3(comp,i,9,numComp,10)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,10)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,10)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,10)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,10)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,10)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,10)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,10)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,10)] + lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,10)] + lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,10)] + lagrange_deriv_7[i] * e[INDEX3(comp,7, [...]
+                            grad[INDEX4(1,comp,i,j,2,numComp,10)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,10)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,10)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,10)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,10)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,10)] + lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,10)] + lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,10)] + lagrange_deriv_7[j] * e[INDEX3(comp,i, [...]
                         }
                     }
                 }
@@ -667,44 +424,19 @@ void Rectangle::gradient_order10(escript::Data& out, const escript::Data& in) co
     const int numComp = in.getDataPointSize();
     out.requireWrite();
     if (!in.actsExpanded()) {
-        memset(out.getSampleDataRW(0), 0, sizeof(double) * numComp * 121 * m_NE[1] * m_NE[0]);
-    } else if (in.getNumDataPointsPerSample() == 1) {
 #pragma omp parallel for
         for (int ei = 0; ei < m_NE[1]; ++ei) {
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
                 for (int comp = 0; comp < numComp; ++comp) {
-                    double a = 0;
-                    double b = 0;
-                    a += lagrange_deriv_0[0] * e[comp];
-                    b += lagrange_deriv_0[0] * e[comp];
-                    a += lagrange_deriv_1[0] * e[comp];
-                    b += lagrange_deriv_1[0] * e[comp];
-                    a += lagrange_deriv_2[0] * e[comp];
-                    b += lagrange_deriv_2[0] * e[comp];
-                    a += lagrange_deriv_3[0] * e[comp];
-                    b += lagrange_deriv_3[0] * e[comp];
-                    a += lagrange_deriv_4[0] * e[comp];
-                    b += lagrange_deriv_4[0] * e[comp];
-                    a += lagrange_deriv_5[0] * e[comp];
-                    b += lagrange_deriv_5[0] * e[comp];
-                    a += lagrange_deriv_6[0] * e[comp];
-                    b += lagrange_deriv_6[0] * e[comp];
-                    a += lagrange_deriv_7[0] * e[comp];
-                    b += lagrange_deriv_7[0] * e[comp];
-                    a += lagrange_deriv_8[0] * e[comp];
-                    b += lagrange_deriv_8[0] * e[comp];
-                    a += lagrange_deriv_9[0] * e[comp];
-                    b += lagrange_deriv_9[0] * e[comp];
-                    a += lagrange_deriv_10[0] * e[comp];
-                    b += lagrange_deriv_10[0] * e[comp];
-                    a *= inv_jac[0];
-                    b *= inv_jac[1];
-                    for (int i = 0; i < 11; ++i) {
-                        for (int j = 0; j < 11; ++j) {
-                            grad[INDEX4(0,comp,j,i,2,numComp,11)] = a;
-                            grad[INDEX4(1,comp,j,i,2,numComp,11)] = b;
+                    const double a = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp] + lagrange_deriv_10[0] * e[comp]) * inv_jac[0];
+                    const double b = (lagrange_deriv_0[0] * e[comp] + lagrange_deriv_1[0] * e[comp] + lagrange_deriv_2[0] * e[comp] + lagrange_deriv_3[0] * e[comp] + lagrange_deriv_4[0] * e[comp] + lagrange_deriv_5[0] * e[comp] + lagrange_deriv_6[0] * e[comp] + lagrange_deriv_7[0] * e[comp] + lagrange_deriv_8[0] * e[comp] + lagrange_deriv_9[0] * e[comp] + lagrange_deriv_10[0] * e[comp]) * inv_jac[1];
+                    for (int j = 0; j < 11; ++j) {
+                        for (int i = 0; i < 11; ++i) {
+                            const index_t ind = INDEX4(0,comp,i,j,2,numComp,11);
+                            grad[ind + 0] = a;
+                            grad[ind + 1] = b;
                         }
                     }
                 }
@@ -716,37 +448,11 @@ void Rectangle::gradient_order10(escript::Data& out, const escript::Data& in) co
             for (int ej = 0; ej < m_NE[0]; ++ej) {
                 const double *e = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
                 double *grad = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
-                for (int i = 0; i < 11; ++i) {
-                    for (int j = 0; j < 11; ++j) {
+                for (int j = 0; j < 11; ++j) {
+                    for (int i = 0; i < 11; ++i) {
                         for (int comp = 0; comp < numComp; ++comp) {
-                            double a = 0;
-                            double b = 0;
-                            a += lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,11)];
-                            b += lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,11)];
-                            a += lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,11)];
-                            b += lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,11)];
-                            a += lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,11)];
-                            b += lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,11)];
-                            a += lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,11)];
-                            b += lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,11)];
-                            a += lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,11)];
-                            b += lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,11)];
-                            a += lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,11)];
-                            b += lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,11)];
-                            a += lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,11)];
-                            b += lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,11)];
-                            a += lagrange_deriv_7[i] * e[INDEX3(comp,7,j,numComp,11)];
-                            b += lagrange_deriv_7[j] * e[INDEX3(comp,i,7,numComp,11)];
-                            a += lagrange_deriv_8[i] * e[INDEX3(comp,8,j,numComp,11)];
-                            b += lagrange_deriv_8[j] * e[INDEX3(comp,i,8,numComp,11)];
-                            a += lagrange_deriv_9[i] * e[INDEX3(comp,9,j,numComp,11)];
-                            b += lagrange_deriv_9[j] * e[INDEX3(comp,i,9,numComp,11)];
-                            a += lagrange_deriv_10[i] * e[INDEX3(comp,10,j,numComp,11)];
-                            b += lagrange_deriv_10[j] * e[INDEX3(comp,i,10,numComp,11)];
-                            a *= inv_jac[0];
-                            grad[INDEX4(0,comp,i,j,2,numComp,11)] = a;
-                            b *= inv_jac[1];
-                            grad[INDEX4(1,comp,i,j,2,numComp,11)] = b;
+                            grad[INDEX4(0,comp,i,j,2,numComp,11)] = (lagrange_deriv_0[i] * e[INDEX3(comp,0,j,numComp,11)] + lagrange_deriv_1[i] * e[INDEX3(comp,1,j,numComp,11)] + lagrange_deriv_2[i] * e[INDEX3(comp,2,j,numComp,11)] + lagrange_deriv_3[i] * e[INDEX3(comp,3,j,numComp,11)] + lagrange_deriv_4[i] * e[INDEX3(comp,4,j,numComp,11)] + lagrange_deriv_5[i] * e[INDEX3(comp,5,j,numComp,11)] + lagrange_deriv_6[i] * e[INDEX3(comp,6,j,numComp,11)] + lagrange_deriv_7[i] * e[INDEX3(comp,7, [...]
+                            grad[INDEX4(1,comp,i,j,2,numComp,11)] = (lagrange_deriv_0[j] * e[INDEX3(comp,i,0,numComp,11)] + lagrange_deriv_1[j] * e[INDEX3(comp,i,1,numComp,11)] + lagrange_deriv_2[j] * e[INDEX3(comp,i,2,numComp,11)] + lagrange_deriv_3[j] * e[INDEX3(comp,i,3,numComp,11)] + lagrange_deriv_4[j] * e[INDEX3(comp,i,4,numComp,11)] + lagrange_deriv_5[j] * e[INDEX3(comp,i,5,numComp,11)] + lagrange_deriv_6[j] * e[INDEX3(comp,i,6,numComp,11)] + lagrange_deriv_7[j] * e[INDEX3(comp,i, [...]
                         }
                     }
                 }
diff --git a/speckley/src/RectangleIntegrals.cpp b/speckley/src/RectangleIntegrals.cpp
index a0f82ee..0589793 100644
--- a/speckley/src/RectangleIntegrals.cpp
+++ b/speckley/src/RectangleIntegrals.cpp
@@ -1,3 +1,21 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <esysUtils/index.h>
 #include <speckley/Rectangle.h>
 
diff --git a/speckley/src/RectangleReductions.cpp b/speckley/src/RectangleReductions.cpp
new file mode 100644
index 0000000..e508100
--- /dev/null
+++ b/speckley/src/RectangleReductions.cpp
@@ -0,0 +1,200 @@
+
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#include <speckley/Rectangle.h>
+
+namespace speckley {
+void Rectangle::reduction_order2(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.333333333333, 1.33333333333, 0.333333333333};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 3; ++i) {
+                    for (int j = 0; j < 3; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,3)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order3(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.166666666667, 0.833333333333, 0.833333333333, 0.166666666667};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 4; ++i) {
+                    for (int j = 0; j < 4; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,4)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order4(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.1, 0.544444444444, 0.711111111111, 0.544444444444, 0.1};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 5; ++i) {
+                    for (int j = 0; j < 5; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,5)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order5(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.0666666666667, 0.378474956298, 0.554858377035, 0.554858377035, 0.378474956298, 0.0666666666667};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 6; ++i) {
+                    for (int j = 0; j < 6; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,6)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order6(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.047619047619, 0.276826047362, 0.43174538121, 0.487619047619, 0.43174538121, 0.276826047362, 0.047619047619};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 7; ++i) {
+                    for (int j = 0; j < 7; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,7)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order7(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.0357142857143, 0.210704227144, 0.341122692484, 0.412458794659, 0.412458794659, 0.341122692484, 0.210704227144, 0.0357142857143};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 8; ++i) {
+                    for (int j = 0; j < 8; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,8)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order8(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.0277777777778, 0.165495361561, 0.2745387125, 0.346428510973, 0.371519274376, 0.346428510973, 0.2745387125, 0.165495361561, 0.0277777777778};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 9; ++i) {
+                    for (int j = 0; j < 9; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,9)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order9(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.0222222222222, 0.133305990851, 0.224889342063, 0.29204268368, 0.327539761184, 0.327539761184, 0.29204268368, 0.224889342063, 0.133305990851, 0.0222222222222};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 10; ++i) {
+                    for (int j = 0; j < 10; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,10)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+void Rectangle::reduction_order10(const escript::Data& in, escript::Data& out) const {
+    const double weights[] = {0.0181818181818, 0.109612273267, 0.18716988178, 0.248048104264, 0.286879124779, 0.300217595456, 0.286879124779, 0.248048104264, 0.18716988178, 0.109612273267, 0.0181818181818};
+    const int numComp = in.getDataPointSize();
+    for (int ei = 0; ei < m_NE[1]; ++ei) {
+        for (int ej = 0; ej < m_NE[0]; ++ej) {
+            const double *e_in = in.getSampleDataRO(INDEX2(ej,ei,m_NE[0]));
+            double *e_out = out.getSampleDataRW(INDEX2(ej,ei,m_NE[0]));
+            for (int comp = 0; comp < numComp; ++comp) {
+                double result = 0;
+                for (int i = 0; i < 11; ++i) {
+                    for (int j = 0; j < 11; ++j) {
+                        result += weights[i] * weights[j] * e_in[INDEX3(comp,j,i,numComp,11)];
+                    }
+                }
+                e_out[comp] += result / 4.;
+            }
+        }
+    }
+}
+
+}
diff --git a/speckley/src/SConscript b/speckley/src/SConscript
index edfa0ec..2f70e08 100644
--- a/speckley/src/SConscript
+++ b/speckley/src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -31,14 +31,18 @@ sources = """
     Brick.cpp
     BrickGradients.cpp
     BrickIntegrals.cpp
+    BrickReductions.cpp
     DefaultAssembler2D.cpp
     DefaultAssembler3D.cpp
     domainhelpers.cpp
     Rectangle.cpp
     RectangleGradients.cpp
     RectangleIntegrals.cpp
+    RectangleReductions.cpp
     SpeckleyDomain.cpp
     SpeckleyException.cpp
+    WaveAssembler2D.cpp
+    WaveAssembler3D.cpp
 """.split()
 
 headers = """
@@ -53,6 +57,8 @@ headers = """
     SpeckleyDomain.h
     SpeckleyException.h
     system_dep.h
+    WaveAssembler2D.h
+    WaveAssembler3D.h
 """.split()
 
 local_env.Prepend(LIBS = ['escript', 'esysUtils'])
diff --git a/speckley/src/Speckley.h b/speckley/src/Speckley.h
index 6fbbd40..6c52a81 100644
--- a/speckley/src/Speckley.h
+++ b/speckley/src/Speckley.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/SpeckleyDomain.cpp b/speckley/src/SpeckleyDomain.cpp
index bd079e1..43a0026 100644
--- a/speckley/src/SpeckleyDomain.cpp
+++ b/speckley/src/SpeckleyDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/SpeckleyDomain.h>
 #include <escript/DataFactory.h>
 #include <escript/FunctionSpaceFactory.h>
@@ -76,6 +80,7 @@ bool SpeckleyDomain::isValidFunctionSpaceType(int fsType) const
         case DegreesOfFreedom:
         case Nodes:
         case Elements:
+        case ReducedElements:
         case Points:
             return true;
         default:
@@ -114,6 +119,8 @@ pair<int,dim_t> SpeckleyDomain::getDataShape(int fsType) const
             return pair<int,dim_t>(1, getNumDOF());
         case Elements:
             return pair<int,dim_t>(ptsPerSample, getNumElements());
+        case ReducedElements:
+            return pair<int,dim_t>(1, getNumElements());
         case Points:
             return pair<int,dim_t>(1, m_diracPoints.size());
         default:
@@ -143,14 +150,16 @@ bool SpeckleyDomain::commonFunctionSpace(const vector<int>& fs, int& resultcode)
     The idea is to use equivalence classes (i.e. types which can be
     interpolated back and forth):
     class 0: DOF <-> Nodes
+    class 1: ReducedDOF <-> ReducedNodes
     class 2: Points
     class 3: Elements
+    class 4: ReducedElements
 
     There is also a set of lines. Interpolation is possible down a line but not
     between lines.
     class 0 and 1 belong to all lines so aren't considered.
     line 0: class 2
-    line 1: class 3
+    line 1: class 3,4
 
     For classes with multiple members (eg class 1) we have vars to record if
     there is at least one instance. e.g. hasnodes is true if we have at least
@@ -161,12 +170,17 @@ bool SpeckleyDomain::commonFunctionSpace(const vector<int>& fs, int& resultcode)
     vector<bool> hasclass(7, false);
     vector<int> hasline(3, 0);
     bool hasnodes=false;
+    bool hasrednodes=false;
     for (size_t i=0; i<fs.size(); ++i) {
         switch (fs[i]) {
             case Nodes: hasnodes=true; // fall through
             case DegreesOfFreedom:
                 hasclass[0]=true;
                 break;
+            case ReducedNodes: hasrednodes=true; // fall through
+            case ReducedDegreesOfFreedom:
+                hasclass[1]=true;
+                break;
             case Points:
                 hasline[0]=1;
                 hasclass[2]=true;
@@ -175,6 +189,10 @@ bool SpeckleyDomain::commonFunctionSpace(const vector<int>& fs, int& resultcode)
                 hasclass[3]=true;
                 hasline[1]=1;
                 break;
+            case ReducedElements:
+                hasclass[4]=true;
+                hasline[1]=1;
+                break;
             default:
                 return false;
         }
@@ -190,9 +208,16 @@ bool SpeckleyDomain::commonFunctionSpace(const vector<int>& fs, int& resultcode)
         if (hasline[0]==1)
             resultcode=Points;
         else if (hasline[1]==1) {
+            if (hasclass[4])
+                resultcode=ReducedElements;
+            else
             resultcode=Elements;
         }
     } else { // numLines==0
+        if (hasclass[1])
+            // something from class 1
+            resultcode=(hasrednodes ? ReducedNodes : ReducedDegreesOfFreedom);
+        else // something from class 0
         resultcode=(hasnodes ? Nodes : DegreesOfFreedom);
     }
     return true;
@@ -212,10 +237,16 @@ bool SpeckleyDomain::probeInterpolationOnDomain(int fsType_source,
         case Nodes:
         case DegreesOfFreedom:
             return true;
+        case ReducedNodes:
+        case ReducedDegreesOfFreedom:
+            return (fsType_target != Nodes &&
+                    fsType_target != DegreesOfFreedom);
         case Elements:
-            return (fsType_target==Elements || fsType_target==Nodes);
+            return (fsType_target==Elements || fsType_target==ReducedElements || fsType_target==Nodes);
         case Points:
             return (fsType_target==fsType_source);
+        case ReducedElements:
+            return (fsType_target==Elements || fsType_target==Nodes);
 
         default: {
             stringstream msg;
@@ -251,8 +282,14 @@ signed char SpeckleyDomain::preferredInterpolationOnDomain(int fsType_source,
         case Nodes:
         case DegreesOfFreedom:
             return 1;
+        case ReducedNodes:
+        case ReducedDegreesOfFreedom:
+            return (fsType_target != Nodes &&
+                    fsType_target != DegreesOfFreedom) ? -1 : 0;
         case Elements:
-            return 0;
+            return (fsType_target==ReducedElements) ? -1 : 0;
+        case ReducedElements:
+            return (fsType_target==Elements) ? 1 : 0;
         case Points:
             return 0;  // other case caught by the if above
         default: {
@@ -286,8 +323,12 @@ void SpeckleyDomain::interpolateOnDomain(escript::Data& target,
     // simplest case: 1:1 copy
     if (inFS==outFS) {
         copyData(target, in);
-    } else if (inFS==Elements && outFS==Nodes) {
-            interpolateElementsOnNodes(target, in);
+    } else if ((inFS==Elements || inFS==ReducedElements) && outFS==Nodes) {
+        interpolateElementsOnNodes(target, in);
+    } else if (inFS==ReducedElements && outFS==Elements) {
+        multiplyData(target, in);
+    } else if (inFS==Elements && outFS==ReducedElements) {
+        reduceElements(target, in);
     } else {
         switch (inFS) {
             case Nodes:
@@ -297,9 +338,11 @@ void SpeckleyDomain::interpolateOnDomain(escript::Data& target,
                         copyData(target, in);
                         break;
                     case Elements:
-                        interpolateNodesOnElements(target, in);
+                        interpolateNodesOnElements(target, in, false);
+                        break;
+                    case ReducedElements:
+                        interpolateNodesOnElements(target, in, true);
                         break;
-
                     case Points:
                         {
                             const dim_t numComp = in.getDataPointSize();
@@ -325,11 +368,12 @@ void SpeckleyDomain::interpolateOnDomain(escript::Data& target,
                         break;
 
                     case Elements:
+                    case ReducedElements:
                         if (getMPISize()==1) {
-                            interpolateNodesOnElements(target, in);
+                            interpolateNodesOnElements(target, in, outFS==ReducedElements);
                         } else {
                             escript::Data contIn(in, escript::continuousFunction(*this));
-                            interpolateNodesOnElements(target, contIn);
+                            interpolateNodesOnElements(target, contIn, outFS==ReducedElements);
                         }
                         break;
 
@@ -407,6 +451,7 @@ void SpeckleyDomain::setToGradient(escript::Data& grad, const escript::Data& arg
     switch (grad.getFunctionSpace().getTypeCode()) {
         case Nodes:
         case Elements:
+        case ReducedElements:
             break;
         default: {
             stringstream msg;
@@ -454,6 +499,7 @@ void SpeckleyDomain::setToIntegrals(vector<double>& integrals, const escript::Da
             }
             break;
         case Elements:
+        case ReducedElements:
             assembleIntegrate(integrals, arg);
             break;
         default: {
@@ -473,6 +519,7 @@ bool SpeckleyDomain::isCellOriented(int fsType) const
         case DegreesOfFreedom:
             return false;
         case Elements:
+        case ReducedElements:
         case Points:
             return true;
         default:
@@ -489,6 +536,7 @@ bool SpeckleyDomain::canTag(int fsType) const
     switch(fsType) {
         case Nodes:
         case Elements:
+        case ReducedElements:
         case Points:
             return true;
         case DegreesOfFreedom:
@@ -543,6 +591,7 @@ int SpeckleyDomain::getTagFromSampleNo(int fsType, index_t sampleNo) const
                 return m_nodeTags[sampleNo];
             break;
         case Elements:
+        case ReducedElements:
             if (m_elementTags.size() > sampleNo)
                 return m_elementTags[sampleNo];
             break;
@@ -565,6 +614,7 @@ int SpeckleyDomain::getNumberOfTagsInUse(int fsType) const
         case Nodes:
             return m_nodeTagsInUse.size();
         case Elements:
+        case ReducedElements:
             return m_elementTagsInUse.size();
         default: {
             stringstream msg;
@@ -581,6 +631,7 @@ const int* SpeckleyDomain::borrowListOfTagsInUse(int fsType) const
         case Nodes:
             return &m_nodeTagsInUse[0];
         case Elements:
+        case ReducedElements:
             return &m_elementTagsInUse[0];
         default: {
             stringstream msg;
@@ -667,7 +718,8 @@ void SpeckleyDomain::addToRHS(escript::Data& rhs, const DataMap& coefs,
                     "addPDEToRHS: Speckley does not support contact elements");
 
     if (rhs.isEmpty()) {
-        if (isNotEmpty("X", coefs) || isNotEmpty("Y", coefs))
+        if (isNotEmpty("X", coefs) || isNotEmpty("du", coefs)
+                    || isNotEmpty("Y", coefs))
             throw SpeckleyException(
                     "addPDEToRHS: right hand side coefficients are provided "
                     "but no right hand side vector given");
@@ -720,6 +772,24 @@ void SpeckleyDomain::copyData(escript::Data& out, const escript::Data& in) const
 }
 
 //protected
+void SpeckleyDomain::multiplyData(escript::Data& out, const escript::Data& in) const
+{
+    const dim_t numComp = in.getDataPointSize();
+    const dim_t dpp = out.getNumDataPointsPerSample();
+    const dim_t numSamples = in.getNumSamples();
+    out.requireWrite();
+#pragma omp parallel for
+    for (index_t i=0; i<numSamples; i++) {
+        const double* src = in.getSampleDataRO(i);
+        double* dest = out.getSampleDataRW(i);
+        for (index_t c=0; c<numComp; c++) {
+            for (index_t q=0; q<dpp; q++)
+                dest[c+q*numComp] = src[c];
+        }
+    }
+}
+
+//protected
 void SpeckleyDomain::updateTagsInUse(int fsType) const
 {
     std::vector<int>* tagsInUse=NULL;
@@ -744,7 +814,7 @@ void SpeckleyDomain::updateTagsInUse(int fsType) const
     tagsInUse->clear();
     int lastFoundValue = numeric_limits<int>::min();
     int minFoundValue, local_minFoundValue;
-    const long numTags = tags->size();
+    const int numTags = tags->size();
 
     while (true) {
         // find smallest value bigger than lastFoundValue
@@ -752,9 +822,8 @@ void SpeckleyDomain::updateTagsInUse(int fsType) const
 #pragma omp parallel private(local_minFoundValue)
         {
             local_minFoundValue = minFoundValue;
-            long i;     // should be size_t but omp mutter mutter
-#pragma omp for schedule(static) private(i) nowait
-            for (i = 0; i < numTags; i++) {
+#pragma omp for schedule(static) nowait
+            for (int i = 0; i < numTags; i++) {
                 const int v = (*tags)[i];
                 if ((v > lastFoundValue) && (v < local_minFoundValue))
                     local_minFoundValue = v;
@@ -792,7 +861,8 @@ void SpeckleyDomain::assemblePDE(escript::AbstractSystemMatrix* mat,
                                escript::Data& rhs, const DataMap& coefs,
                                Assembler_ptr assembler) const
 {
-    if (rhs.isEmpty() && isNotEmpty("X", coefs) && isNotEmpty("Y", coefs))
+    if (rhs.isEmpty() && (isNotEmpty("X", coefs) || isNotEmpty("du", coefs)) 
+            && isNotEmpty("Y", coefs))
         throw SpeckleyException("assemblePDE: right hand side coefficients are "
                     "provided but no right hand side vector given");
 
@@ -914,6 +984,7 @@ void SpeckleyDomain::assemblePDEDirac(escript::AbstractSystemMatrix* mat,
         nComp = mat->getColumnBlockSize();
     }
 
+    rhs.requireWrite();
     for (int i = 0; i < m_diracPoints.size(); i++) { //only for this rank
         const IndexVector rowIndex(1, m_diracPoints[i].node);
         if (yNotEmpty) {
diff --git a/speckley/src/SpeckleyDomain.h b/speckley/src/SpeckleyDomain.h
index 04dfb6e..eac328b 100644
--- a/speckley/src/SpeckleyDomain.h
+++ b/speckley/src/SpeckleyDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -17,16 +17,6 @@
 #ifndef __Speckley_DOMAIN_H__
 #define __Speckley_DOMAIN_H__
 
-#ifdef BADPYTHONMACROS
-// This hack is required for BSD/OSX builds with python 2.7
-// (and possibly others).  It must be the first include.
-// From bug reports online it seems that python redefines
-// some c macros that are functions in c++.
-// c++ doesn't like that!
-#include <Python.h>
-#undef BADPYTHONMACROS
-#endif
-
 #include <boost/python/tuple.hpp>
 #include <boost/python/list.hpp>
 
@@ -284,7 +274,7 @@ public:
 
     /**
        \brief
-       returns locations in the FEM nodes
+       returns locations in the SEM nodes
     */
     virtual escript::Data getX() const;
 
@@ -392,7 +382,7 @@ public:
        returns a function with reduced integration order FunctionSpace code
     */
     virtual int getReducedFunctionCode() const {
-        throw SpeckleyException("Speckley does not support reduced functionspaces");
+        return ReducedElements;
     }
 
     /**
@@ -409,7 +399,7 @@ public:
        FunctionSpace code
     */
     virtual int getReducedFunctionOnBoundaryCode() const {
-        throw SpeckleyException("Speckley does not support reduced function spaces");
+        throw SpeckleyException("Speckley does not support face elements");
     }
 
     /**
@@ -471,10 +461,8 @@ public:
        returns the identifier of the matrix type to be used for the global
        stiffness matrix when a particular solver, package, preconditioner,
        and symmetric matrix is used
-       \param solver
-       \param preconditioner
-       \param package
-       \param symmetry
+       \param options a python object containing the solver, package,
+                preconditioner and symmetry
     */
     virtual int getSystemMatrixTypeId(const boost::python::object& options) const;
 
@@ -758,6 +746,9 @@ protected:
     void addPoints(const std::vector<double>& coords,
                    const std::vector<int>& tags);
 
+    /// expands ReducedFunction (in) to Function (out)
+    void multiplyData(escript::Data& out, const escript::Data& in) const;
+
     /***********************************************************************/
 
     /// returns the number of nodes per MPI rank
@@ -782,7 +773,8 @@ protected:
 
     /// interpolates data on nodes in 'in' onto elements in 'out'
     virtual void interpolateNodesOnElements(escript::Data& out,
-                                            const escript::Data& in) const = 0;
+                                            const escript::Data& in,
+                                            bool reduced) const = 0;
 
     /// interpolates data on elements in 'in' onto nodes in 'out'
     virtual void interpolateElementsOnNodes(escript::Data& out,
@@ -790,6 +782,9 @@ protected:
 
     virtual dim_t getDofOfNode(dim_t node) const = 0;
 
+    /// interpolates from Element -> ReducedElement
+    virtual void reduceElements(escript::Data& out, const escript::Data& in) const = 0;
+
 #ifdef ESYS_MPI
     /// sum up overlapping edges of MPI ranks and average if average is true
     virtual void balanceNeighbours(escript::Data& data, bool average) const = 0;
diff --git a/speckley/src/SpeckleyException.cpp b/speckley/src/SpeckleyException.cpp
index 5dfa473..be150b5 100644
--- a/speckley/src/SpeckleyException.cpp
+++ b/speckley/src/SpeckleyException.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/SpeckleyException.h>
 
 namespace speckley {
diff --git a/speckley/src/SpeckleyException.h b/speckley/src/SpeckleyException.h
index ad06677..544b10d 100644
--- a/speckley/src/SpeckleyException.h
+++ b/speckley/src/SpeckleyException.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/DefaultAssembler2D.cpp b/speckley/src/WaveAssembler2D.cpp
similarity index 71%
copy from speckley/src/DefaultAssembler2D.cpp
copy to speckley/src/WaveAssembler2D.cpp
index 37cb07c..9506c28 100644
--- a/speckley/src/DefaultAssembler2D.cpp
+++ b/speckley/src/WaveAssembler2D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,7 +13,12 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
-#include <speckley/DefaultAssembler2D.h>
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
+#include <speckley/WaveAssembler2D.h>
 #include <speckley/domainhelpers.h>
 #include <esysUtils/index.h>
 
@@ -110,37 +115,31 @@ using escript::Data;
 
 namespace speckley {
 
-void DefaultAssembler2D::collateFunctionSpaceTypes(std::vector<int>& fsTypes,
+void WaveAssembler2D::collateFunctionSpaceTypes(std::vector<int>& fsTypes,
                                    const DataMap& coefs) const
 {
-    if (isNotEmpty("A", coefs))
-        fsTypes.push_back(coefs.find("A")->second.getFunctionSpace().getTypeCode());
-    if (isNotEmpty("B", coefs))
-        fsTypes.push_back(coefs.find("B")->second.getFunctionSpace().getTypeCode());
-    if (isNotEmpty("C", coefs))
-        fsTypes.push_back(coefs.find("C")->second.getFunctionSpace().getTypeCode());
     if (isNotEmpty("D", coefs))
         fsTypes.push_back(coefs.find("D")->second.getFunctionSpace().getTypeCode());
-    if (isNotEmpty("X", coefs))
-        fsTypes.push_back(coefs.find("X")->second.getFunctionSpace().getTypeCode());
     if (isNotEmpty("Y", coefs))
         fsTypes.push_back(coefs.find("Y")->second.getFunctionSpace().getTypeCode());
+    if (isNotEmpty("du", coefs))
+        fsTypes.push_back(coefs.find("du")->second.getFunctionSpace().getTypeCode());
 }
 
-void DefaultAssembler2D::assemblePDESingle(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESingle(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESingle(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESingle(mat, rhs, A, B, C, D, du, Y);
 
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const 
 {
     const Data& d = unpackData("d", coefs);
@@ -148,19 +147,19 @@ void DefaultAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
     assemblePDEBoundarySingle(mat, rhs, d, y);
 }
 
-void DefaultAssembler2D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESingleReduced(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESingleReduced(mat, rhs, A, B, C, D, du, Y);
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySingleReduced(
+void WaveAssembler2D::assemblePDEBoundarySingleReduced(
                                         AbstractSystemMatrix* mat, Data& rhs,
                                         const DataMap& coefs) const
 {
@@ -169,19 +168,21 @@ void DefaultAssembler2D::assemblePDEBoundarySingleReduced(
     assemblePDEBoundarySingleReduced(mat, rhs, d, y);
 }
 
-void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
+    if (!unpackData("X", coefs).isEmpty())
+        throw SpeckleyException("Wave assembler does not support X");
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESystem(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESystem(mat, rhs, A, B, C, D, du, Y);
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& d = unpackData("d", coefs);
@@ -189,19 +190,19 @@ void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
     assemblePDEBoundarySystem(mat, rhs, d, y);
 }
 
-void DefaultAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESystemReduced(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESystemReduced(mat, rhs, A, B, C, D, du, Y);
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
+void WaveAssembler2D::assemblePDEBoundarySystemReduced(
                                         AbstractSystemMatrix* mat, Data& rhs,
                                         const DataMap& coefs) const
 {
@@ -210,10 +211,10 @@ void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
     assemblePDEBoundarySystemReduced(mat, rhs, d, y);
 }
 
-void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                                      Data& rhs, const Data& A, const Data& B,
                                      const Data& C, const Data& D,
-                                     const Data& X, const Data& Y) const
+                                     const Data& du, const Data& Y) const
 {
     if (!(A.isEmpty() && B.isEmpty() && C.isEmpty()))
         throw SpeckleyException("Speckley does not support PDEs using A, B or C");
@@ -243,7 +244,7 @@ void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
     }
     const index_t d_indices[2] = {0,size-1};
 
-    if (!D.isEmpty() && (!X.isEmpty() || !Y.isEmpty()))
+    if (!D.isEmpty() && (!du.isEmpty() || !Y.isEmpty()))
         throw SpeckleyException("Speckley does not support adding left and right sides concurrently");
     
     for (dim_t colouring = 0; colouring < 2; colouring++) {
@@ -278,40 +279,61 @@ void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
                     }
                 }
                 
-                if (!X.isEmpty()) {
-                    const double *e = X.getSampleDataRO(e_index);
-                    if (X.actsExpanded()) {
-                        for (index_t comp = 0; comp < numComp; comp++) {
-                            for (short qy = 0; qy < quads; qy++) {
-                                for (short qx = 0; qx < quads; qx++) {
-                                    double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-                                    double res_a = 0, res_b = 0;
-                                    for (short k = 0; k < quads; k++) {
-                                        res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                                * e[INDEX4(comp,0,k,qy,numComp,2,quads)]; //X(i1),k,qy
-                                        res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                                * e[INDEX4(comp,1,qx,k,numComp,2,quads)]; //X(i2),qx,k
-                                    }
-/* X */ out[comp] += 2 * volume_product 
-            * (res_a * weights[qy] / m_dx[0] + res_b * weights[qx] / m_dx[1]);
+                if (!du.isEmpty()) {
+                    const double *du_p = du.getSampleDataRO(e_index);
+                    const double c11_v = -c11.getSampleDataRO(e_index)[0];
+                    const double c13_v = -c13.getSampleDataRO(e_index)[0];
+                    const double c33_v = -c33.getSampleDataRO(e_index)[0];
+                    const double diagonal = (
+                            isHTI ? -c66.getSampleDataRO(e_index)[0]
+                                  : -c44.getSampleDataRO(e_index)[0]);
+
+                    
+                    if (du.actsExpanded()) {
+                        for (short qy = 0; qy < quads; qy++) { //a
+                            for (short qx = 0; qx < quads; qx++) { //b
+                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
+                                double res_a = 0, res_b = 0; //comp 0
+                                double res_c = 0, res_d = 0; //comp 1
+                                for (short k = 0; k < quads; k++) {
+#define SI(_x_,_y_,_qx_,_qy_) INDEX4((_x_),(_y_),(_qx_),(_qy_),numComp,2,quads)
+                                    res_a += weights[k] * all_lagrange_derivs[order-2][qx][k] 
+                                            * (c11_v*du_p[SI(0,0,k,qy)] + c13_v*du_p[SI(1,1,k,qy)]);
+                                    res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                            * diagonal*( du_p[SI(0,1,qx,k)] + du_p[SI(1,0,qx,k)] );
+                                            
+                                    res_c += weights[k] * all_lagrange_derivs[order-2][qx][k] 
+                                            * diagonal*(du_p[SI(0,1,k,qy)] + du_p[SI(1,0,k,qy)]);
+                                    res_d += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                            * (c13_v*du_p[SI(0,0,qx,k)] + c33_v*du_p[SI(1,1,qx,k)]);
+#undef SI
                                 }
+                                out[0] += 2 * volume_product 
+                                        * (res_a * weights[qy] / m_dx[0] + res_b * weights[qx] / m_dx[1]);
+                                out[1] += 2 * volume_product 
+                                        * (res_c * weights[qy] / m_dx[0] + res_d * weights[qx] / m_dx[1]);
                             }
                         }
                     } else { //constant
-                        for (index_t comp = 0; comp < numComp; comp++) {
-                            for (short qy = 0; qy < quads; qy++) {
-                                for (short qx = 0; qx < quads; qx++) {
-                                    double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-                                    double res_a = 0, res_b = 0;
-                                    for (short k = 0; k < quads; k++) {
-                                        res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                                * e[INDEX2(comp,0,numComp)]; //X(i1)
-                                        res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                                * e[INDEX2(comp,1,numComp)]; //X(i2)
-                                    }
-/* X */ out[comp] += 2 * volume_product 
-            * (res_a * weights[qy] / m_dx[0] + res_b * weights[qx] / m_dx[1]);
+                        for (short qy = 0; qy < quads; qy++) {
+                            for (short qx = 0; qx < quads; qx++) {
+                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
+                                double res_a = 0, res_b = 0; //comp 0
+                                double res_c = 0, res_d = 0; //comp 1
+                                for (short k = 0; k < quads; k++) {
+                                    res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                            * (c11_v*du_p[0] + c13_v*du_p[2]);
+                                    res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                            * diagonal*(du_p[1] + du_p[2]);
+                                    res_c += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                            * diagonal*(du_p[1] + du_p[2]);
+                                    res_d += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                            * (c13_v*du_p[0] + c33_v*du_p[3]);
                                 }
+                                out[0] += 2 * volume_product 
+                                        * (res_a * weights[qy] / m_dx[0] + res_b * weights[qx] / m_dx[1]);
+                                out[1] += 2 * volume_product 
+                                        * (res_c * weights[qy] / m_dx[0] + res_d * weights[qx] / m_dx[1]);
                             }
                         }
                     }
@@ -346,35 +368,35 @@ void DefaultAssembler2D::assemblePDESystem(AbstractSystemMatrix* mat,
     }
 }
 
-void DefaultAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
                                     Data& rhs, const Data& A, const Data& B,
                                     const Data& C, const Data& D,
-                                    const Data& X, const Data& Y) const
+                                    const Data& du, const Data& Y) const
 {
     throw SpeckleyException("Speckley does not support reduced functionspaces");
     
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
                                 Data& rhs, const Data& d, const Data& y) const
 {
     throw SpeckleyException("Speckley does not support boundary functionspaces");
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySingleReduced(
+void WaveAssembler2D::assemblePDEBoundarySingleReduced(
                                         AbstractSystemMatrix* mat, Data& rhs,
                                         const Data& d, const Data& y) const
 {
     throw SpeckleyException("Speckley does not support reduced functionspaces");
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                Data& rhs, const Data& d, const Data& y) const
 {
     throw SpeckleyException("Speckley does not support boundary functionspaces");
 }
 
-void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
+void WaveAssembler2D::assemblePDEBoundarySystemReduced(
                                          AbstractSystemMatrix* mat, Data& rhs,
                                          const Data& d, const Data& y) const
 {
@@ -382,116 +404,19 @@ void DefaultAssembler2D::assemblePDEBoundarySystemReduced(
 }
 
 //protected
-void DefaultAssembler2D::assemblePDESingle(AbstractSystemMatrix *mat,
+void WaveAssembler2D::assemblePDESingle(AbstractSystemMatrix *mat,
         escript::Data& rhs, const escript::Data& A, const escript::Data& B,
         const escript::Data& C, const escript::Data& D,
-        const escript::Data& X, const escript::Data& Y) const
+        const escript::Data& du, const escript::Data& Y) const
 {
-    if (!(A.isEmpty() && B.isEmpty() && C.isEmpty()))
-        throw SpeckleyException("Speckley does not support PDEs using A, B or C");
-    int order = domain->m_order;
-    const double *weights = all_weights[order-2];
-    const double volume_product = m_dx[0]*m_dx[1]/4.;
-    const int NE0 = m_NE[0];
-    const int NE1 = m_NE[1];
-    const int quads = order + 1;
-    const int max_x = m_NN[0];
-    rhs.requireWrite();
-    
-    
-    if (!D.isEmpty() && (!X.isEmpty() || !Y.isEmpty()))
-        throw SpeckleyException("Speckley does not support adding left and right sides concurrently");
-    
-    for (dim_t colouring = 0; colouring < 2; colouring++) {
-#pragma omp parallel for
-        for (dim_t ey = colouring; ey < NE1; ey += 2) {
-            for (dim_t ex = 0; ex < NE0; ex++) {
-                const index_t e_index = INDEX2(ex,ey,NE0); //element number for Elements
-                const index_t start = order * (INDEX2(ex, ey, max_x)); //node start for Nodes
-
-                if (!D.isEmpty()) {
-                    const double *e = D.getSampleDataRO(e_index);
-                    if (D.actsExpanded()) {
-                        for (short qy = 0; qy < quads; qy++) {
-                            for (short qx = 0; qx < quads; qx++) {
-                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-/* D */ out[0] += volume_product * weights[qx] * weights[qy] 
-                    * e[INDEX2(qx, qy, quads)]; //D,qx,qy
-                            }
-                        }
-                    } else {    // constant form
-                        for (short qy = 0; qy < quads; qy++) {
-                            for (short qx = 0; qx < quads; qx++) {
-                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-/* D */ out[0] += volume_product * weights[qx] * weights[qy]  * e[0]; //D
-                            }
-                        }
-                    }
-                }
-                
-                if (!X.isEmpty()) {
-                    const double *e = X.getSampleDataRO(e_index);
-                    if (X.actsExpanded()) {
-                        for (short qy = 0; qy < quads; qy++) {
-                            for (short qx = 0; qx < quads; qx++) {
-                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-                                double res_a = 0, res_b = 0;
-                                for (short k = 0; k < quads; k++) {
-                                    res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                            * e[INDEX3(0,k,qy,2,quads)]; //X(1),k,qy
-                                    res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                            * e[INDEX3(1,qx,k,2,quads)]; //X(2),qx,k
-                                }
-/* X */ out[0] += 2 * volume_product * (res_a * weights[qy] / m_dx[0] + res_b * weights[qx] / m_dx[1]);
-                            }
-                        }
-                    } else { //constant
-                        for (short qy = 0; qy < quads; qy++) {
-                            for (short qx = 0; qx < quads; qx++) {
-                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-                                double res_a = 0, res_b = 0;
-                                for (short k = 0; k < quads; k++) {
-                                    res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                            * e[0]; //X(1)
-                                    res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                            * e[1]; //X(2)
-                                }
-/* X */ out[0] += 2 * volume_product 
-            * (res_a * weights[qy] / m_dx[0] + res_b * weights[qx] / m_dx[1]);
-                            }
-                        }
-                    }
-                }
-                
-                if (!Y.isEmpty()) {
-                    const double *e = Y.getSampleDataRO(e_index);
-                    if (Y.actsExpanded()) {
-                        for (short qy = 0; qy < quads; qy++) {
-                            for (short qx = 0; qx < quads; qx++) {
-                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-/* Y */ out[0] += volume_product * weights[qx] * weights[qy] 
-                    * e[INDEX2(qx, qy, quads)]; //Y,qx,qy
-                            }
-                        }
-                    } else {    // constant form
-                        for (short qy = 0; qy < quads; qy++) {
-                            for (short qx = 0; qx < quads; qx++) {
-                                double *out = rhs.getSampleDataRW(start + INDEX2(qx,qy,max_x));
-/* Y */ out[0] += volume_product * weights[qx] * weights[qy] * e[0]; //Y
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
+    throw SpeckleyException("WaveAssembler does not support assemblePDESingle()");
 }
 
 //protected
-void DefaultAssembler2D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
+void WaveAssembler2D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
                                     Data& rhs, const Data& A, const Data& B,
                                     const Data& C, const Data& D,
-                                    const Data& X, const Data& Y) const
+                                    const Data& du, const Data& Y) const
 {
     throw SpeckleyException("Speckley does not support reduced functionspaces");
 }
diff --git a/speckley/src/DefaultAssembler2D.h b/speckley/src/WaveAssembler2D.h
similarity index 64%
copy from speckley/src/DefaultAssembler2D.h
copy to speckley/src/WaveAssembler2D.h
index 5bec1d6..ed3e60a 100644
--- a/speckley/src/DefaultAssembler2D.h
+++ b/speckley/src/WaveAssembler2D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,28 +13,76 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
-#ifndef __SPECKLEY_DEFAULTASSEMBLER2D_H__
-#define __SPECKLEY_DEFAULTASSEMBLER2D_H__
+#ifndef __SPECKLEY_WAVE_ASSEMBLER_2D_H__
+#define __SPECKLEY_WAVE_ASSEMBLER_2D_H__
 
 #include <speckley/Rectangle.h>
 
 namespace speckley {
 
 
-class DefaultAssembler2D : public AbstractAssembler
+class WaveAssembler2D : public AbstractAssembler
 {
 public:
-    DefaultAssembler2D(escript::const_Domain_ptr dom, const double *dx,
-                       const dim_t *NE, const dim_t *NN)
+    WaveAssembler2D(escript::const_Domain_ptr dom, const double *dx,
+                       const dim_t *NE, const dim_t *NN, const DataMap& c)
         : AbstractAssembler(),
         m_dx(dx),
         m_NE(NE),
         m_NN(NN)
     {
         domain = boost::static_pointer_cast<const Rectangle>(dom);
+        isHTI = isVTI = false;
+        DataMap::const_iterator a = c.find("c12"), b = c.find("c23");
+        if (c.find("c11") == c.end()
+                    || c.find("c13") == c.end() || c.find("c33") == c.end()
+                    || c.find("c44") == c.end() || c.find("c66") == c.end()
+                    || (a == c.end() && b == c.end()))
+            throw SpeckleyException("required constants missing for WaveAssembler");
+
+        if (a != c.end() && b != c.end()) {
+            throw SpeckleyException("WaveAssembler3D() doesn't support general form waves");
+        } else if (a == c.end()) {
+            c23 = b->second;
+            isHTI = true;
+            if (c23.getFunctionSpace().getTypeCode() != ReducedElements) {
+                throw SpeckleyException("C tensor elements must be reduced");
+            }
+            if (c23.isEmpty()) {
+                throw SpeckleyException("C tensor elements must not be empty");
+            }
+        } else if (b == c.end()) {
+            c12 = a->second;
+            isVTI = true;
+            if (c12.getFunctionSpace().getTypeCode() != ReducedElements) {
+                throw SpeckleyException("C tensor elements must be reduced");
+            }
+            if (c12.isEmpty()) {
+                throw SpeckleyException("C tensor elements must not be empty");
+            }
+        } // final else case taken care of with the missing constants above
+        c11 = c.find("c11")->second;
+        c13 = c.find("c13")->second;
+        c33 = c.find("c33")->second;
+        c44 = c.find("c44")->second;
+        c66 = c.find("c66")->second;
+        if (c11.getFunctionSpace().getTypeCode() != ReducedElements
+                || c13.getFunctionSpace().getTypeCode() != ReducedElements
+                || c33.getFunctionSpace().getTypeCode() != ReducedElements
+                || c44.getFunctionSpace().getTypeCode() != ReducedElements 
+                || c66.getFunctionSpace().getTypeCode() != ReducedElements) {
+            throw SpeckleyException("C tensor elements must be reduced");
+        }
+        if (c11.isEmpty()
+                || c13.isEmpty()
+                || c33.isEmpty()
+                || c44.isEmpty() 
+                || c66.isEmpty()) {
+            throw SpeckleyException("C tensor elements must not be empty");
+        }
     }
 
-    ~DefaultAssembler2D() {}
+    ~WaveAssembler2D() {}
 
     /* The default SpeckleyDomain assemblers, with original signatures */
     
@@ -43,7 +91,7 @@ public:
     virtual void assemblePDESingle(escript::AbstractSystemMatrix* mat, escript::Data& rhs,
             const escript::Data& A, const escript::Data& B,
             const escript::Data& C, const escript::Data& D,
-            const escript::Data& X, const escript::Data& Y) const;
+            const escript::Data& du, const escript::Data& Y) const;
 
     /// assembles boundary conditions of a single PDE into the system matrix
     /// 'mat' and the right hand side 'rhs'
@@ -56,7 +104,7 @@ public:
     virtual void assemblePDESingleReduced(escript::AbstractSystemMatrix* mat,
             escript::Data& rhs, const escript::Data& A, const escript::Data& B,
             const escript::Data& C, const escript::Data& D,
-            const escript::Data& X, const escript::Data& Y) const;
+            const escript::Data& du, const escript::Data& Y) const;
 
     /// assembles boundary conditions of a single PDE with reduced order into
     /// the system matrix 'mat' and the right hand side 'rhs'
@@ -69,7 +117,7 @@ public:
     virtual void assemblePDESystem(escript::AbstractSystemMatrix* mat, escript::Data& rhs,
             const escript::Data& A, const escript::Data& B,
             const escript::Data& C, const escript::Data& D,
-            const escript::Data& X, const escript::Data& Y) const;
+            const escript::Data& du, const escript::Data& Y) const;
 
     /// assembles boundary conditions of a system of PDEs into the system
     /// matrix 'mat' and the right hand side 'rhs'
@@ -82,7 +130,7 @@ public:
     virtual void assemblePDESystemReduced(escript::AbstractSystemMatrix* mat,
             escript::Data& rhs, const escript::Data& A, const escript::Data& B,
             const escript::Data& C, const escript::Data& D,
-            const escript::Data& X, const escript::Data& Y) const;
+            const escript::Data& du, const escript::Data& Y) const;
 
     /// assembles boundary conditions of a system of PDEs with reduced order
     /// into the system matrix 'mat' and the right hand side 'rhs'
@@ -127,6 +175,8 @@ protected:
     const double *m_dx;
     const dim_t *m_NE;
     const dim_t *m_NN;
+    bool isHTI, isVTI;
+    escript::Data c11, c12, c13, c23, c33, c44, c66;
 };
 
 } // namespace speckley
diff --git a/speckley/src/DefaultAssembler3D.cpp b/speckley/src/WaveAssembler3D.cpp
similarity index 58%
copy from speckley/src/DefaultAssembler3D.cpp
copy to speckley/src/WaveAssembler3D.cpp
index 942f808..f186431 100644
--- a/speckley/src/DefaultAssembler3D.cpp
+++ b/speckley/src/WaveAssembler3D.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,7 +13,12 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
-#include <speckley/DefaultAssembler3D.h>
+
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
+#include <speckley/WaveAssembler3D.h>
 #include <speckley/domainhelpers.h>
 #include <esysUtils/index.h>
 
@@ -110,37 +115,31 @@ using escript::Data;
 
 namespace speckley {
 
-void DefaultAssembler3D::collateFunctionSpaceTypes(std::vector<int>& fsTypes,
+void WaveAssembler3D::collateFunctionSpaceTypes(std::vector<int>& fsTypes,
                                    const DataMap& coefs) const
 {
-    if (isNotEmpty("A", coefs))
-        fsTypes.push_back(coefs.find("A")->second.getFunctionSpace().getTypeCode());
-    if (isNotEmpty("B", coefs))
-        fsTypes.push_back(coefs.find("B")->second.getFunctionSpace().getTypeCode());
-    if (isNotEmpty("C", coefs))
-        fsTypes.push_back(coefs.find("C")->second.getFunctionSpace().getTypeCode());
     if (isNotEmpty("D", coefs))
         fsTypes.push_back(coefs.find("D")->second.getFunctionSpace().getTypeCode());
-    if (isNotEmpty("X", coefs))
-        fsTypes.push_back(coefs.find("X")->second.getFunctionSpace().getTypeCode());
+    if (isNotEmpty("du", coefs))
+        fsTypes.push_back(coefs.find("du")->second.getFunctionSpace().getTypeCode());
     if (isNotEmpty("Y", coefs))
         fsTypes.push_back(coefs.find("Y")->second.getFunctionSpace().getTypeCode());
 }
 
-void DefaultAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDESingle(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESingle(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESingle(mat, rhs, A, B, C, D, du, Y);
 
 }
 
-void DefaultAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const 
 {
     const Data& d = unpackData("d", coefs);
@@ -148,19 +147,19 @@ void DefaultAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
     assemblePDEBoundarySingle(mat, rhs, d, y);
 }
 
-void DefaultAssembler3D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESingleReduced(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESingleReduced(mat, rhs, A, B, C, D, du, Y);
 }
 
-void DefaultAssembler3D::assemblePDEBoundarySingleReduced(
+void WaveAssembler3D::assemblePDEBoundarySingleReduced(
                                         AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
@@ -169,19 +168,19 @@ void DefaultAssembler3D::assemblePDEBoundarySingleReduced(
     assemblePDEBoundarySingleReduced(mat, rhs, d, y);
 }
 
-void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESystem(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESystem(mat, rhs, A, B, C, D, du, Y);
 }
 
-void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& d = unpackData("d", coefs);
@@ -189,19 +188,19 @@ void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
     assemblePDEBoundarySystem(mat, rhs, d, y);
 }
 
-void DefaultAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
     const Data& A = unpackData("A", coefs);
     const Data& B = unpackData("B", coefs);
     const Data& C = unpackData("C", coefs);
     const Data& D = unpackData("D", coefs);
-    const Data& X = unpackData("X", coefs);
+    const Data& du = unpackData("du", coefs);
     const Data& Y = unpackData("Y", coefs);
-    assemblePDESystemReduced(mat, rhs, A, B, C, D, X, Y);
+    assemblePDESystemReduced(mat, rhs, A, B, C, D, du, Y);
 }
 
-void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
+void WaveAssembler3D::assemblePDEBoundarySystemReduced(
                                         AbstractSystemMatrix* mat,
                                         Data& rhs, const DataMap& coefs) const
 {
@@ -211,10 +210,10 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
 }
 
 
-void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
+void WaveAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                                            const Data& A, const Data& B,
                                            const Data& C, const Data& D,
-                                           const Data& X, const Data& Y) const
+                                           const Data& du, const Data& Y) const
 {
     int order = domain->m_order;
     const double *weights = all_weights[order-2];
@@ -250,7 +249,7 @@ void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
     }
     const index_t d_indices[3] = {0,mid,size-1};
 
-    if (!D.isEmpty() && (!X.isEmpty() || !Y.isEmpty()))
+    if (!D.isEmpty() && (!du.isEmpty() || !Y.isEmpty()))
         throw SpeckleyException("assemblers can't deal with adding both lhs and rhs right now");
     
     for (dim_t colouring = 0; colouring < 2; colouring++) {
@@ -289,52 +288,181 @@ void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
                         }
                     }
                     
-                    if (!X.isEmpty()) {
-                        const double *e = X.getSampleDataRO(e_index);
-                        if (X.actsExpanded()) {
-                            for (index_t comp = 0; comp < numComp; comp++) {
+                    if (!du.isEmpty()) {
+                        if (isHTI) {
+                            const double *du_p = du.getSampleDataRO(e_index);
+                            const double c11_v = -c11.getSampleDataRO(e_index)[0];
+                            const double c13_v = -c13.getSampleDataRO(e_index)[0];
+                            const double c23_v = -c23.getSampleDataRO(e_index)[0];
+                            const double c33_v = -c33.getSampleDataRO(e_index)[0];
+                            const double c44_v = -c44.getSampleDataRO(e_index)[0];
+                            const double c66_v = -c66.getSampleDataRO(e_index)[0];
+                            if (du.actsExpanded()) {
                                 for (short qz = 0; qz < quads; qz++) {
                                     for (short qy = 0; qy < quads; qy++) {
                                         for (short qx = 0; qx < quads; qx++) {
                                             double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-                                            double res_a = 0, res_b = 0, res_c = 0;
+                                            double res_a[3] = {0}, res_b[3] = {0}, res_c[3] = {0};
+#define SI(_x_,_y_,_qx_,_qy_,_qz_) INDEX5((_x_),(_y_),(_qx_),(_qy_),(_qz_),3,3,quads,quads)
                                             for (short k = 0; k < quads; k++) {
-                                                res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                                        * e[INDEX5(comp,0,k,qy,qz,numComp,3,quads,quads)]; //X(i1),k,qy,qz
-                                                res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                                        * e[INDEX5(comp,1,qx,k,qz,numComp,3,quads,quads)]; //X(i2),qx,k,qz
-                                                res_c += weights[k] * all_lagrange_derivs[order-2][qz][k]
-                                                        * e[INDEX5(comp,2,qx,qy,k,numComp,3,quads,quads)]; //X(i3),qx,qy,k
+                                                res_a[0] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * (c11_v*du_p[SI(0,0,k,qy,qz)]+c13_v*(du_p[SI(1,1,k,qy,qz)] + du_p[SI(2,2,k,qy,qz)]));
+                                                res_b[0] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c66_v*(du_p[SI(0,1,qx,k,qz)] + du_p[SI(1,0,qx,k,qz)]);
+                                                res_c[0] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c66_v*(du_p[SI(0,2,qx,qy,k)] + du_p[SI(2,0,qx,qy,k)]);
+                                                        
+                                                res_a[1] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c66_v*(du_p[SI(1,0,k,qy,qz)] + du_p[SI(0,1,k,qy,qz)]);
+                                                res_b[1] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * (c13_v*du_p[SI(0,0,qx,k,qz)] + c33_v*du_p[SI(1,1,qx,k,qz)] + c23_v*du_p[SI(2,2,qx,k,qz)]);
+                                                res_c[1] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c44_v*(du_p[SI(1,2,qx,qy,k)] + du_p[SI(2,1,qx,qy,k)]);
+                                                        
+                                                res_a[2] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c66_v*(du_p[SI(2,0,k,qy,qz)] + du_p[SI(0,2,k,qy,qz)]);
+                                                res_b[2] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c44_v*(du_p[SI(2,1,qx,k,qz)] + du_p[SI(1,2,qx,k,qz)]);
+                                                res_c[2] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * (c13_v*du_p[SI(0,0,qx,qy,k)] +c23_v*du_p[SI(1,1,qx,qy,k)] + c33_v*du_p[SI(2,2,qx,qy,k)]);
+                                            }
+#undef SI
+                                            for (short i = 0; i < 3; i++) {
+                                                out[i] += 2 * volume_product * (
+                                                        res_a[i] * weights[qy] * weights[qz] / m_dx[0] 
+                                                      + res_b[i] * weights[qx] * weights[qz] / m_dx[1] 
+                                                      + res_c[i] * weights[qx] * weights[qy] / m_dx[2]
+                                                    );
+                                            }
+                                        }
+                                    }
+                                }
+                            } else { //constant
+                                for (short qz = 0; qz < quads; qz++) {
+                                    for (short qy = 0; qy < quads; qy++) {
+                                        for (short qx = 0; qx < quads; qx++) {
+                                            double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
+                                            double res_a[3] = {0}, res_b[3] = {0}, res_c[3] = {0};
+#define SI(_x_,_y_) INDEX2((_x_),(_y_),3)
+                                            for (short k = 0; k < quads; k++) {
+                                                res_a[0] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * (c11_v*du_p[SI(0,0)]+c13_v*(du_p[SI(1,1)] + du_p[SI(2,2)]));
+                                                res_b[0] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c66_v*(du_p[SI(0,1)] + du_p[SI(1,0)]);
+                                                res_c[0] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c66_v*(du_p[SI(0,2)] + du_p[SI(2,0)]);
+                                                        
+                                                res_a[1] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c66_v*(du_p[SI(1,0)] + du_p[SI(0,1)]);
+                                                res_b[1] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * (c13_v*du_p[SI(0,0)] + c33_v*du_p[SI(1,1)] + c23_v*du_p[SI(2,2)]);
+                                                res_c[1] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c44_v*(du_p[SI(1,2)] + du_p[SI(2,1)]);
+                                                        
+                                                res_a[2] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c66_v*(du_p[SI(2,0)] + du_p[SI(0,2)]);
+                                                res_b[2] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c44_v*(du_p[SI(2,1)] + du_p[SI(1,2)]);
+                                                res_c[2] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * (c13_v*du_p[SI(0,0)] +c23_v*du_p[SI(1,1)] + c33_v*du_p[SI(2,2)]);
+                                            }
+#undef SI
+                                            for (short comp = 0; comp < 3; comp++) {
+                                                out[comp] += 2 * volume_product * (
+                                                    res_a[comp] * weights[qy] * weights[qz] / m_dx[0] 
+                                                  + res_b[comp] * weights[qx] * weights[qz] / m_dx[1] 
+                                                  + res_c[comp] * weights[qx] * weights[qy] / m_dx[2]
+                                                );
                                             }
-/* X */ out[comp] += 2 * volume_product * (
-            res_a * weights[qy] * weights[qz] / m_dx[0] 
-          + res_b * weights[qx] * weights[qz] / m_dx[1] 
-          + res_c * weights[qx] * weights[qy] / m_dx[2]
-        );
                                         }
                                     }
                                 }
                             }
-                        } else { //constant
-                            for (index_t comp = 0; comp < numComp; comp++) {
+                        } else { //VTI
+                            const double *du_p = du.getSampleDataRO(e_index);
+                            const double c11_v = -c11.getSampleDataRO(e_index)[0];
+                            const double c12_v = -c12.getSampleDataRO(e_index)[0];
+                            const double c13_v = -c13.getSampleDataRO(e_index)[0];
+                            const double c33_v = -c33.getSampleDataRO(e_index)[0];
+                            const double c44_v = -c44.getSampleDataRO(e_index)[0];
+                            const double c66_v = -c66.getSampleDataRO(e_index)[0];
+                            if (du.actsExpanded()) {
                                 for (short qz = 0; qz < quads; qz++) {
                                     for (short qy = 0; qy < quads; qy++) {
                                         for (short qx = 0; qx < quads; qx++) {
                                             double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-                                            double res_a = 0, res_b = 0, res_c = 0;
+                                            double res_a[3] = {0}, res_b[3] = {0}, res_c[3] = {0};
+#define SI(_x_,_y_,_qx_,_qy_,_qz_) INDEX5((_x_),(_y_),(_qx_),(_qy_),(_qz_),3,3,quads,quads)
                                             for (short k = 0; k < quads; k++) {
-                                                res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                                        * e[INDEX2(comp,0,numComp)]; //X(i1)
-                                                res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                                        * e[INDEX2(comp,1,numComp)]; //X(i2)
-                                                res_c += weights[k] * all_lagrange_derivs[order-2][qz][k]
-                                                        * e[INDEX2(comp,2,numComp)]; //X(i3)
+                                                res_a[0] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * (c11_v*du_p[SI(0,0,k,qy,qz)]+c12_v*du_p[SI(1,1,k,qy,qz)] + c13_v*du_p[SI(2,2,k,qy,qz)]);
+                                                res_b[0] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c66_v*(du_p[SI(0,1,qx,k,qz)] + du_p[SI(1,0,qx,k,qz)]);
+                                                res_c[0] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c44_v*(du_p[SI(0,2,qx,qy,k)] + du_p[SI(2,0,qx,qy,k)]);
+                                                        
+                                                res_a[1] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c66_v*(du_p[SI(1,0,k,qy,qz)] + du_p[SI(0,1,k,qy,qz)]);
+                                                res_b[1] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * (c12_v*du_p[SI(0,0,qx,k,qz)] + c11_v*du_p[SI(1,1,qx,k,qz)] + c13_v*du_p[SI(2,2,qx,k,qz)]);
+                                                res_c[1] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c44_v*(du_p[SI(1,2,qx,qy,k)] + du_p[SI(2,1,qx,qy,k)]);
+                                                        
+                                                res_a[2] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c44_v*(du_p[SI(2,0,k,qy,qz)] + du_p[SI(0,2,k,qy,qz)]);
+                                                res_b[2] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c44_v*(du_p[SI(2,1,qx,k,qz)] + du_p[SI(1,2,qx,k,qz)]);
+                                                res_c[2] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * (c13_v*(du_p[SI(0,0,qx,qy,k)] + du_p[SI(1,1,qx,qy,k)]) + c33_v*du_p[SI(2,2,qx,qy,k)]);
+                                            }
+#undef SI
+                                            for (short i = 0; i < 3; i++) {
+                                                out[i] += 2 * volume_product * (
+                                                        res_a[i] * weights[qy] * weights[qz] / m_dx[0] 
+                                                      + res_b[i] * weights[qx] * weights[qz] / m_dx[1] 
+                                                      + res_c[i] * weights[qx] * weights[qy] / m_dx[2]
+                                                    );
+                                            }
+                                        }
+                                    }
+                                }
+                            } else { //constant
+                                for (short qz = 0; qz < quads; qz++) {
+                                    for (short qy = 0; qy < quads; qy++) {
+                                        for (short qx = 0; qx < quads; qx++) {
+                                            double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
+                                            double res_a[3] = {0}, res_b[3] = {0}, res_c[3] = {0};
+#define SI(_x_,_y_) INDEX2((_x_),(_y_),3)
+                                            for (short k = 0; k < quads; k++) {
+                                                res_a[0] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * (c11_v*du_p[SI(0,0)]+c12_v*du_p[SI(1,1)] + c13_v*du_p[SI(2,2)]);
+                                                res_b[0] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c66_v*(du_p[SI(0,1)] + du_p[SI(1,0)]);
+                                                res_c[0] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c44_v*(du_p[SI(0,2)] + du_p[SI(2,0)]);
+                                                        
+                                                res_a[1] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c66_v*(du_p[SI(1,0)] + du_p[SI(0,1)]);
+                                                res_b[1] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * (c12_v*du_p[SI(0,0)] + c11_v*du_p[SI(1,1)] + c13_v*du_p[SI(2,2)]);
+                                                res_c[1] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * c44_v*(du_p[SI(1,2)] + du_p[SI(2,1)]);
+                                                        
+                                                res_a[2] += weights[k] * all_lagrange_derivs[order-2][qx][k]
+                                                        * c44_v*(du_p[SI(2,0)] + du_p[SI(0,2)]);
+                                                res_b[2] += weights[k] * all_lagrange_derivs[order-2][qy][k] 
+                                                        * c44_v*(du_p[SI(2,1)] + du_p[SI(1,2)]);
+                                                res_c[2] += weights[k] * all_lagrange_derivs[order-2][qz][k]
+                                                        * (c13_v*(du_p[SI(0,0)] + du_p[SI(1,1)]) + c33_v*du_p[SI(2,2)]);
+                                            }
+#undef SI
+                                            for (short comp = 0; comp < 3; comp++) {
+                                                out[comp] += 2 * volume_product * (
+                                                    res_a[comp] * weights[qy] * weights[qz] / m_dx[0] 
+                                                  + res_b[comp] * weights[qx] * weights[qz] / m_dx[1] 
+                                                  + res_c[comp] * weights[qx] * weights[qy] / m_dx[2]
+                                                );
                                             }
-/* X */ out[comp] += 2 * volume_product * (
-            res_a * weights[qy] * weights[qz] / m_dx[0] 
-          + res_b * weights[qx] * weights[qz] / m_dx[1] 
-          + res_c * weights[qx] * weights[qy] / m_dx[2]
-        );
                                         }
                                     }
                                 }
@@ -377,38 +505,38 @@ void DefaultAssembler3D::assemblePDESystem(AbstractSystemMatrix* mat, Data& rhs,
 }
 
 //protected
-void DefaultAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDESystemReduced(AbstractSystemMatrix* mat,
                                      Data& rhs, const Data& A, const Data& B,
                                      const Data& C, const Data& D,
-                                     const Data& X, const Data& Y) const
+                                     const Data& du, const Data& Y) const
 {
     throw SpeckleyException("system reduced assemblers not implemented yet");
     
 }
 
 //protected
-void DefaultAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDEBoundarySingle(AbstractSystemMatrix* mat,
                                 Data& rhs, const Data& d, const Data& y) const
 {
     throw SpeckleyException("boundary single assemblers not implemented yet");
 }
 
 //protected
-void DefaultAssembler3D::assemblePDEBoundarySingleReduced(
+void WaveAssembler3D::assemblePDEBoundarySingleReduced(
                                         AbstractSystemMatrix* mat, Data& rhs,
                                         const Data& d, const Data& y) const
 {
     throw SpeckleyException("boundary single reduced assemblers not implemented yet");
 }
 
-void DefaultAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDEBoundarySystem(AbstractSystemMatrix* mat,
                                Data& rhs, const Data& d, const Data& y) const
 {
     throw SpeckleyException("boundary system assemblers not implemented yet");
 }
 
 //protected
-void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
+void WaveAssembler3D::assemblePDEBoundarySystemReduced(
                                         AbstractSystemMatrix* mat, Data& rhs,
                                         const Data& d, const Data& y) const
 {
@@ -416,142 +544,19 @@ void DefaultAssembler3D::assemblePDEBoundarySystemReduced(
 }
 
 //protected
-void DefaultAssembler3D::assemblePDESingle(escript::AbstractSystemMatrix *mat,
+void WaveAssembler3D::assemblePDESingle(escript::AbstractSystemMatrix *mat,
         escript::Data& rhs, const escript::Data& A, const escript::Data& B,
         const escript::Data& C, const escript::Data& D,
-        const escript::Data& X, const escript::Data& Y) const
+        const escript::Data& du, const escript::Data& Y) const
 {
-    int order = domain->m_order;
-    const double *weights = all_weights[order-2];
-    const double volume_product = m_dx[0]*m_dx[1]*m_dx[2]/8.;
-    const int NE0 = m_NE[0];
-    const int NE1 = m_NE[1];
-    const int NE2 = m_NE[2];
-    const int quads = order + 1;
-    const int max_x = m_NN[0];
-    const int max_y = m_NN[1];
-    rhs.requireWrite();
-    
-    
-    if (!D.isEmpty() && (!X.isEmpty() || !Y.isEmpty()))
-        throw SpeckleyException("assemblers can't deal with adding both lhs and rhs right now");
-    
-    for (dim_t colouring = 0; colouring < 2; colouring++) {
-#pragma omp parallel for
-        for (dim_t ez = colouring; ez < NE2; ez += 2) {
-            for (dim_t ey = 0; ey < NE1; ey++) {
-                for (dim_t ex = 0; ex < NE0; ex++) {
-                    const index_t e_index = INDEX3(ex,ey,ez,NE0,NE1); //element number for Elements
-                    const index_t start = order * (INDEX3(ex, ey, ez, max_x, max_y)); //node start for Nodes
-                    if (!D.isEmpty()) {
-                        const double *e = D.getSampleDataRO(e_index);
-                        if (D.actsExpanded()) {
-                            for (short qz = 0; qz < quads; qz++) {
-                                for (short qy = 0; qy < quads; qy++) {
-                                    for (short qx = 0; qx < quads; qx++) {
-                                        double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-/* D */ out[0] += volume_product * weights[qx] * weights[qy] * weights[qz]
-        * e[INDEX3(qx, qy, qz, quads, quads)]; //D,qx,qy,qz
-                                    }
-                                }
-                            }
-                        } else { //constant
-                            for (short qz = 0; qz < quads; qz++) {
-                                for (short qy = 0; qy < quads; qy++) {
-                                    for (short qx = 0; qx < quads; qx++) {
-                                        double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-/* D */ out[0] += volume_product * weights[qx] * weights[qy] * weights[qz]
-                    * e[0]; //D
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    
-                    if (!X.isEmpty()) {
-                        const double *e = X.getSampleDataRO(e_index);
-                        if (X.actsExpanded()) {
-                            for (short qz = 0; qz < quads; qz++) {
-                                for (short qy = 0; qy < quads; qy++) {
-                                    for (short qx = 0; qx < quads; qx++) {
-                                        double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-                                        double res_a = 0, res_b = 0, res_c = 0;
-                                        for (short k = 0; k < quads; k++) {
-                                            res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                                    * e[INDEX4(0,k,qy,qz,3,quads,quads)]; //X(1),k,qy,qz
-                                            res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                                    * e[INDEX4(1,qx,k,qz,3,quads,quads)]; //X(2),qx,k,qz
-                                            res_c += weights[k] * all_lagrange_derivs[order-2][qz][k]
-                                                    * e[INDEX4(2,qx,qy,k,3,quads,quads)]; //X(3),qx,qy,k
-                                        }
-/* X */ out[0] += 2 * volume_product * (
-            res_a * weights[qy] * weights[qz] / m_dx[0] 
-          + res_b * weights[qx] * weights[qz] / m_dx[1] 
-          + res_c * weights[qx] * weights[qy] / m_dx[2]
-        );
-                                    }
-                                }
-                            }
-                        } else {
-                            for (short qz = 0; qz < quads; qz++) {
-                                for (short qy = 0; qy < quads; qy++) {
-                                    for (short qx = 0; qx < quads; qx++) {
-                                        double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-                                        double res_a = 0, res_b = 0, res_c = 0;
-                                        for (short k = 0; k < quads; k++) {
-                                            res_a += weights[k] * all_lagrange_derivs[order-2][qx][k]
-                                                    * e[0]; //X(1)
-                                            res_b += weights[k] * all_lagrange_derivs[order-2][qy][k] 
-                                                    * e[1]; //X(2)
-                                            res_c += weights[k] * all_lagrange_derivs[order-2][qz][k]
-                                                    * e[2]; //X(3)
-                                        }
-/* X */ out[0] += 2 * volume_product * (
-            res_a * weights[qy] * weights[qz] / m_dx[0] 
-          + res_b * weights[qx] * weights[qz] / m_dx[1] 
-          + res_c * weights[qx] * weights[qy] / m_dx[2]
-        );
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    
-                    if (!Y.isEmpty()) {
-                        const double *e = Y.getSampleDataRO(e_index);
-                        if (Y.actsExpanded()) {
-                            for (short qz = 0; qz < quads; qz++) {
-                                for (short qy = 0; qy < quads; qy++) {
-                                    for (short qx = 0; qx < quads; qx++) {
-                                        double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-/* Y */ out[0] += volume_product * weights[qx] * weights[qy] * weights[qz]
-                * e[INDEX3(qx, qy, qz, quads, quads)]; //Y,qx,qy,qz
-                                    }
-                                }
-                            }
-                        } else { //constant
-                            for (short qz = 0; qz < quads; qz++) {
-                                for (short qy = 0; qy < quads; qy++) {
-                                    for (short qx = 0; qx < quads; qx++) {
-                                        double *out = rhs.getSampleDataRW(start + INDEX3(qx,qy,qz,max_x,max_y));
-/* Y */ out[0] += volume_product * weights[qx] * weights[qy] * weights[qz]
-                    * e[0]; //Y
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
+    throw SpeckleyException("Wave assemblers do not support assemblePDESingle()");
 }
 
 //protected
-void DefaultAssembler3D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
+void WaveAssembler3D::assemblePDESingleReduced(AbstractSystemMatrix* mat,
                                     Data& rhs, const Data& A, const Data& B,
                                     const Data& C, const Data& D,
-                                    const Data& X, const Data& Y) const
+                                    const Data& du, const Data& Y) const
 {
     throw SpeckleyException("single reduced assemblers not implemented yet");
 }
diff --git a/speckley/src/DefaultAssembler3D.h b/speckley/src/WaveAssembler3D.h
similarity index 68%
copy from speckley/src/DefaultAssembler3D.h
copy to speckley/src/WaveAssembler3D.h
index b3d7aae..eb933ef 100644
--- a/speckley/src/DefaultAssembler3D.h
+++ b/speckley/src/WaveAssembler3D.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -13,8 +13,8 @@
 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
 *
 *****************************************************************************/
-#ifndef __SPECKLEY_DEFAULTASSEMBLER3D_H__
-#define __SPECKLEY_DEFAULTASSEMBLER3D_H__
+#ifndef __SPECKLEY_WAVE_ASSEMBLER_3D_H__
+#define __SPECKLEY_WAVE_ASSEMBLER_3D_H__
 
 #include <map>
 #include <escript/Data.h>
@@ -26,20 +26,68 @@
 namespace speckley {
 
 
-class DefaultAssembler3D : public AbstractAssembler
+class WaveAssembler3D : public AbstractAssembler
 {
 public:
-    DefaultAssembler3D(escript::const_Domain_ptr dom, const double *dx,
-                       const dim_t *NE, const dim_t *NN)
+    WaveAssembler3D(escript::const_Domain_ptr dom, const double *dx,
+                       const dim_t *NE, const dim_t *NN, const DataMap& c)
         : AbstractAssembler(),
         m_dx(dx),
         m_NE(NE),
         m_NN(NN)
     {
         domain = boost::static_pointer_cast<const Brick>(dom);
+        isHTI = isVTI = false;
+        DataMap::const_iterator a = c.find("c12"), b = c.find("c23");
+        if (c.find("c11") == c.end()
+                    || c.find("c13") == c.end() || c.find("c33") == c.end()
+                    || c.find("c44") == c.end() || c.find("c66") == c.end()
+                    || (a == c.end() && b == c.end()))
+            throw SpeckleyException("required constants missing for WaveAssembler");
+
+        if (a != c.end() && b != c.end()) {
+            throw SpeckleyException("WaveAssembler3D() doesn't support general form waves");
+        } else if (a == c.end()) {
+            c23 = b->second;
+            isHTI = true;
+            if (c23.getFunctionSpace().getTypeCode() != ReducedElements) {
+                throw SpeckleyException("C tensor elements must be reduced");
+            }
+            if (c23.isEmpty()) {
+                throw SpeckleyException("C tensor elements must not be empty");
+            }
+        } else if (b == c.end()) {
+            c12 = a->second;
+            isVTI = true;
+            if (c12.getFunctionSpace().getTypeCode() != ReducedElements) {
+                throw SpeckleyException("C tensor elements must be reduced");
+            }
+            if (c12.isEmpty()) {
+                throw SpeckleyException("C tensor elements must not be empty");
+            }
+        } // final else case taken care of with the missing constants above
+        c11 = c.find("c11")->second;
+        c13 = c.find("c13")->second;
+        c33 = c.find("c33")->second;
+        c44 = c.find("c44")->second;
+        c66 = c.find("c66")->second;
+        if (c11.getFunctionSpace().getTypeCode() != ReducedElements
+                || c13.getFunctionSpace().getTypeCode() != ReducedElements
+                || c33.getFunctionSpace().getTypeCode() != ReducedElements
+                || c44.getFunctionSpace().getTypeCode() != ReducedElements 
+                || c66.getFunctionSpace().getTypeCode() != ReducedElements) {
+            throw SpeckleyException("C tensor elements must be reduced");
+        }
+        if (c11.isEmpty()
+                || c13.isEmpty()
+                || c33.isEmpty()
+                || c44.isEmpty() 
+                || c66.isEmpty()) {
+            throw SpeckleyException("C tensor elements must not be empty");
+        }
     }
 
-    ~DefaultAssembler3D() {}
+    ~WaveAssembler3D() {}
 
     /* The default SpeckleyDomain assemblers, with original signatures */
     
@@ -128,9 +176,11 @@ protected:
     const double *m_dx;
     const dim_t *m_NE;
     const dim_t *m_NN;
+    bool isHTI, isVTI;
+    escript::Data c11, c12, c13, c23, c33, c44, c66;
 };
 
 } // namespace speckley
 
-#endif // __SPECKLEY_DEFAULTASSEMBLER3D_H__
+#endif // __SPECKLEY_WAVE_ASSEMBLER_3D_H__
 
diff --git a/speckley/src/domainhelpers.cpp b/speckley/src/domainhelpers.cpp
index 1d3b66d..96ce56e 100644
--- a/speckley/src/domainhelpers.cpp
+++ b/speckley/src/domainhelpers.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/domainhelpers.h>
 #include <speckley/SpeckleyException.h>
 #include <cmath>
diff --git a/speckley/src/domainhelpers.h b/speckley/src/domainhelpers.h
index 8a71be2..7a948e4 100644
--- a/speckley/src/domainhelpers.h
+++ b/speckley/src/domainhelpers.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/lagrange_functions.h b/speckley/src/lagrange_functions.h
index cb4cdae..7becdf3 100644
--- a/speckley/src/lagrange_functions.h
+++ b/speckley/src/lagrange_functions.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/speckley/src/speckleycpp.cpp b/speckley/src/speckleycpp.cpp
index d74efef..2b8a079 100644
--- a/speckley/src/speckleycpp.cpp
+++ b/speckley/src/speckleycpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <speckley/AbstractAssembler.h>
 #include <speckley/Brick.h>
 #include <speckley/Rectangle.h>
@@ -381,16 +385,18 @@ BOOST_PYTHON_MODULE(speckleycpp)
         .def("dump", &speckley::SpeckleyDomain::dump, args("filename"),
                 "Dumps the mesh to a file with the given name.")
         .def("getGridParameters", &speckley::SpeckleyDomain::getGridParameters,
-"Returns the tuple (origin, spacing, elements) where the entries are tuples:\n"
-"``origin``=the coordinates of the domain's global origin,\n"
-"``spacing``=the element size (=node spacing) of the domain,\n"
-"``elements``=the global number of elements in all dimensions\n\n"
-":rtype: ``tuple``")
+            "Returns the tuple (origin, spacing, elements) where the entries are tuples:\n"
+            "``origin`` the coordinates of the domain's global origin,\n"
+            "``spacing`` the element size (=node spacing) of the domain,\n"
+            "``elements`` the global number of elements in all dimensions\n\n"
+            ":rtype: ``tuple``")
         .def("getDescription", &speckley::SpeckleyDomain::getDescription,
-":return: a description for this domain\n:rtype: ``string``")
+            ":return: a description for this domain\n:rtype: ``string``")
         .def("getDim", &speckley::SpeckleyDomain::getDim, ":rtype: ``int``")
         .def("getDataShape", &speckley::SpeckleyDomain::getDataShape, args("functionSpaceCode"),
-":return: a pair (dps, ns) where dps=the number of data points per sample, and ns=the number of samples\n:rtype: ``tuple``")
+            ":return: a pair (dps, ns) where dps is the number of data points"
+            " per sample, and ns isthe number of samples\n"
+            ":rtype: ``tuple``")
         .def("getNumDataPointsGlobal", &speckley::SpeckleyDomain::getNumDataPointsGlobal,
 ":return: the number of data points summed across all MPI processes\n"
 ":rtype: ``int``")
@@ -399,13 +405,13 @@ BOOST_PYTHON_MODULE(speckleycpp)
             "adds a PDE to the system, results depend on domain\n\n"
             ":param mat:\n:type mat: `OperatorAdapter`\n"
             ":param rhs:\n:type rhs: `Data`\n"
-            ":param data:\ntype data: `list`")
+            ":param data:\n:type data: `list`")
         .def("addToRHS",&speckley::SpeckleyDomain::addToRHSFromPython,
             args("rhs", "data"),
             "adds a PDE onto the stiffness matrix mat and a rhs, "
             "results depends on domain\n\n"
             ":param rhs:\n:type rhs: `Data`\n"
-            ":param data:\ntype data: `list`")
+            ":param data:\n:type data: `list`")
         .def("getOrder",&speckley::SpeckleyDomain::getOrder,
             ":return: the order of the domain\n"
             ":rtype: ``int``")
diff --git a/speckley/src/system_dep.h b/speckley/src/system_dep.h
index 6fb0b2a..4a0972a 100644
--- a/speckley/src/system_dep.h
+++ b/speckley/src/system_dep.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -17,20 +17,7 @@
 #ifndef __SPECKLEY_SYSTEM_DEP_H__
 #define __SPECKLEY_SYSTEM_DEP_H__
 
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-/*
- * The Intel compiler on windows has an "improved" math library compared to
- * the usual Visual C++ one. In particular it has acosh and other similar
- * functions which aren't implemented in Visual C++ math.h.
- * Note you will get a compile time error if any other header (including
- * system ones) includes math.h whilst mathimf.h has been included.
- * As a result system_dep.h must be included FIRST at all times (this
- * prevents math.h from being included).
- */
-#   include <mathimf.h>
-#else
-#   include <cmath>
-#endif
+#include <cmath>
 
 #define Speckley_DLL_API
 
diff --git a/speckley/test/SConscript b/speckley/test/SConscript
index 6b13f31..402906a 100644
--- a/speckley/test/SConscript
+++ b/speckley/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/speckley/test/python/SConscript b/speckley/test/python/SConscript
index 43cbe9b..f60c4fe 100644
--- a/speckley/test/python/SConscript
+++ b/speckley/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -39,6 +39,8 @@ env.Alias('py_tests', [os.path.splitext(x)[0]+'.passed' for x in testruns])
 program = local_env.RunPyUnitTest(testruns)
 Depends(program, py_wrapper_lib)
 Depends(program, 'build_py_tests')
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # Add a group of tests
 from grouptest import *
diff --git a/speckley/test/python/run_SpeckleyRipleyCoupler.py b/speckley/test/python/run_SpeckleyRipleyCoupler.py
index 7ba653d..1db24a4 100644
--- a/speckley/test/python/run_SpeckleyRipleyCoupler.py
+++ b/speckley/test/python/run_SpeckleyRipleyCoupler.py
@@ -3,7 +3,7 @@ from __future__ import division
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@ from __future__ import division
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -55,6 +55,34 @@ class Test_ripleyCoupler(unittest.TestCase):
         sX = interpolate(sinput, Function(s))
         return actual - interpolate(sX, Function(r)) #actual - interpo...
 
+    def badInterpolations(self, speckley, ripley):
+        FS = Function(speckley)
+        FR = Function(ripley)
+        #bad speck -> good rip
+        with self.assertRaises(RuntimeError):
+            interpolate(speckley.getX(), FR)
+        with self.assertRaises(RuntimeError):
+            interpolate(Data(5, ReducedFunction(speckley)), FR)
+        #good speck -> bad rip
+        with self.assertRaises(RuntimeError):
+            interpolate(Data(5, FS), ReducedFunction(ripley))
+        with self.assertRaises(RuntimeError):
+            interpolate(Data(5, FS), ContinuousFunction(ripley))
+
+    def test_Rectangle_non_Function(self):
+        for order in range(2, 11):
+            coupler = SpeckleyToRipley(2, (2*getMPISizeWorld()*order,order),
+                    order=order, lengths=[3.*getMPISizeWorld(),2.])
+            self.badInterpolations(coupler.getSpeckley(), coupler.getRipley())
+
+    def test_Brick_non_Function(self):
+        for order in range(2, 11):
+            #values here are arbitrary, just has to be Bricks
+            coupler = SpeckleyToRipley(3, (2*getMPISizeWorld()*order,order,order),
+                    order=order, lengths=[3.*getMPISizeWorld(),2.,2.])
+            self.badInterpolations(coupler.getSpeckley(), coupler.getRipley())
+
+
     def test_Rectangle(self):
         for order in range(2,11):
             coupler = SpeckleyToRipley(2, (2*getMPISizeWorld()*order,order),
diff --git a/speckley/test/python/run_customAssemblersOnSpeckley.py b/speckley/test/python/run_customAssemblersOnSpeckley.py
new file mode 100644
index 0000000..9650b7c
--- /dev/null
+++ b/speckley/test/python/run_customAssemblersOnSpeckley.py
@@ -0,0 +1,269 @@
+
+##############################################################################
+#
+# Copyright (c) 2003-2015 by The University of Queensland
+# http://www.uq.edu.au
+#
+# Primary Business: Queensland, Australia
+# Licensed under the Open Software License version 3.0
+# http://www.opensource.org/licenses/osl-3.0.php
+#
+# Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+# Development 2012-2013 by School of Earth Sciences
+# Development from 2014 by Centre for Geoscience Computing (GeoComp)
+#
+##############################################################################
+
+from __future__ import print_function, division
+
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
+http://www.uq.edu.au
+Primary Business: Queensland, Australia"""
+__license__="""Licensed under the Open Software License version 3.0
+http://www.opensource.org/licenses/osl-3.0.php"""
+__url__="https://launchpad.net/escript-finley"
+
+import esys.escriptcore.utestselect as unittest
+from esys.escriptcore.testing import *
+from esys.escript import *
+from esys.speckley import Rectangle, Brick
+from esys.escript.linearPDEs import LameEquation, LinearPDESystem, WavePDE
+from esys.downunder import HTIWave, VTIWave, Ricker
+
+EXPANDED, SCALAR, CONSTANT = range(3)
+
+class SpeckleyWaveAssemblerTestBase(unittest.TestCase):
+    def generate_fast_HTI_PDE_solution(self, domain):
+        pde = WavePDE(domain, [("c11", self.c11),
+                    ("c23", self.c23), ("c13", self.c13), ("c33", self.c33),
+                    ("c44", self.c44), ("c66", self.c66)])
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+        dim = pde.getDim()
+        X = domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+
+        pde.setValue(D=D, y_dirac=y, du=du)
+        return pde.getSolution()
+
+    def generate_slow_HTI_PDE_solution(self, domain):
+        pde = LinearPDESystem(domain)
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+
+        dim = pde.getDim()
+        X = domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+        pde.setValue(X=pde.createCoefficient('X'))
+        sigma = pde.getCoefficient('X')
+        if dim == 3:
+            e11=du[0,0]
+            e22=du[1,1]
+            e33=du[2,2]
+
+            sigma[0,0]=self.c11*e11+self.c13*(e22+e33)
+            sigma[1,1]=self.c13*e11+self.c33*e22+self.c23*e33
+            sigma[2,2]=self.c13*e11+self.c23*e22+self.c33*e33
+
+            s=self.c44*(du[2,1]+du[1,2])
+            sigma[1,2]=s
+            sigma[2,1]=s
+
+            s=self.c66*(du[2,0]+du[0,2])
+            sigma[0,2]=s
+            sigma[2,0]=s
+
+            s=self.c66*(du[0,1]+du[1,0])
+            sigma[0,1]=s
+            sigma[1,0]=s
+
+        else:
+            e11=du[0,0]
+            e22=du[1,1]
+            sigma[0,0]=self.c11*e11+self.c13*e22
+            sigma[1,1]=self.c13*e11+self.c33*e22
+
+            s=self.c66*(du[1,0]+du[0,1])
+            sigma[0,1]=s
+            sigma[1,0]=s
+
+        pde.setValue(D=D, X=-sigma, y_dirac=y)
+        return pde.getSolution()
+
+    def generate_fast_VTI_PDE_solution(self, domain):
+        pde = WavePDE(domain, [("c11", self.c11),
+                    ("c12", self.c12), ("c13", self.c13), ("c33", self.c33),
+                    ("c44", self.c44), ("c66", self.c66)])
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+        dim = pde.getDim()
+
+        X = domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+
+        pde.setValue(D=D, y_dirac=y, du=du)
+        return pde.getSolution()
+
+    def generate_slow_VTI_PDE_solution(self, domain):
+        pde = LinearPDESystem(domain)
+        pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING)
+        pde.setSymmetryOn()
+        dim = pde.getDim()
+
+        dim = pde.getDim()
+        X = domain.getX()
+        y = Vector([2.,3.,4.][:dim], DiracDeltaFunctions(domain))
+        du = grad(X*X)
+        D = 2500.*kronecker(dim)
+        pde.setValue(X=pde.createCoefficient('X'))
+        sigma = pde.getCoefficient('X')
+        
+        if dim == 3:
+            e11=du[0,0]
+            e22=du[1,1]
+            e33=du[2,2]
+            sigma[0,0]=self.c11*e11+self.c12*e22+self.c13*e33
+            sigma[1,1]=self.c12*e11+self.c11*e22+self.c13*e33
+            sigma[2,2]=self.c13*(e11+e22)+self.c33*e33
+
+            s=self.c44*(du[2,1]+du[1,2])
+            sigma[1,2]=s
+            sigma[2,1]=s             
+
+            s=self.c44*(du[2,0]+du[0,2])
+            sigma[0,2]=s
+            sigma[2,0]=s
+
+            s=self.c66*(du[0,1]+du[1,0])
+            sigma[0,1]=s
+            sigma[1,0]=s
+        else:
+            e11=du[0,0]
+            e22=du[1,1]
+            sigma[0,0]=self.c11*e11+self.c13*e22
+            sigma[1,1]=self.c13*e11+self.c33*e22
+            s=self.c44*(du[1,0]+du[0,1])
+            sigma[0,1]=s
+            sigma[1,0]=s
+
+        pde.setValue(D=D, X=-sigma, y_dirac=y)
+        return pde.getSolution()
+
+    def run_HTI_assembly(self, domain):
+        model = HTIWave(domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True,
+                disable_fast_assemblers=True)
+        self.assertFalse(model.fastAssembler) #ensure the arg is obeyed
+
+        model = HTIWave(domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True)
+        self.assertTrue(model.fastAssembler) #ensure fast is actually used
+
+        slow = self.generate_slow_HTI_PDE_solution(domain)
+        fast = self.generate_fast_HTI_PDE_solution(domain)
+
+        self.assertLess(Lsup(fast - slow), 1e-12*Lsup(slow)) #comparison between them
+
+    def run_VTI_assembly(self, domain):
+        model = VTIWave(domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True,
+                disable_fast_assemblers=True)
+        self.assertFalse(model.fastAssembler) #ensure the arg is obeyed
+
+        model = VTIWave(domain, self.V_p, self.V_s, self.wavelet, "source",
+                source_vector=[0,0,1], eps=0., gamma=0., delta=0.,
+                rho=2000., absorption_zone=None, lumping=True)
+        self.assertTrue(model.fastAssembler) #ensure fast is actually used
+        
+        slow = self.generate_slow_VTI_PDE_solution(domain)
+        fast = self.generate_fast_VTI_PDE_solution(domain)
+
+        self.assertLess(Lsup(fast - slow), 1e-12*Lsup(slow)) #comparison between them
+
+    def test_Function_params(self):
+        for domain in self.domains:
+            self.V_p = Data(2500., (), Function(domain))
+            self.V_s = Data(1250., (), Function(domain))
+            self.c11 = Data(11., (), Function(domain))
+            self.c12 = Data(12., (), Function(domain))
+            self.c13 = Data(13., (), Function(domain))
+            self.c23 = Data(23., (), Function(domain))
+            self.c33 = Data(33., (), Function(domain))
+            self.c44 = Data(44., (), Function(domain))
+            self.c66 = Data(66., (), Function(domain))
+            for i in [self.V_p, self.V_s, self.c11, self.c12, self.c13, self.c23,
+                    self.c33, self.c44, self.c66]:
+                i.expand()
+            with self.assertRaises(RuntimeError) as e:
+                self.run_HTI_assembly(domain)
+            self.assertTrue("C tensor elements must be reduced" in str(e.exception))
+            with self.assertRaises(RuntimeError) as e:
+                self.run_VTI_assembly(domain)
+            self.assertTrue("C tensor elements must be reduced" in str(e.exception))
+    
+    def test_ReducedFunction_params(self):
+        for domain in self.domains:
+            self.V_p = Data(2500., (), ReducedFunction(domain))
+            self.V_s = Data(1250., (), ReducedFunction(domain))
+            self.c11 = Data(11., (), ReducedFunction(domain))
+            self.c12 = Data(12., (), ReducedFunction(domain))
+            self.c13 = Data(13., (), ReducedFunction(domain))
+            self.c23 = Data(23., (), ReducedFunction(domain))
+            self.c33 = Data(33., (), ReducedFunction(domain))
+            self.c44 = Data(44., (), ReducedFunction(domain))
+            self.c66 = Data(66., (), ReducedFunction(domain))
+            for i in [self.V_p, self.V_s, self.c11, self.c12, self.c13, self.c23,
+                    self.c33, self.c44, self.c66]:
+                i.expand()
+            self.run_HTI_assembly(domain)
+            self.run_VTI_assembly(domain)
+
+    def test_Constant_params(self):
+        for domain in self.domains:
+            self.V_p = Scalar(2500., ReducedFunction(domain))
+            self.V_s = Scalar(1250., ReducedFunction(domain))
+            self.c11 = Scalar(11., ReducedFunction(domain))
+            self.c12 = Scalar(12., ReducedFunction(domain))
+            self.c13 = Scalar(13., ReducedFunction(domain))
+            self.c23 = Scalar(23., ReducedFunction(domain))
+            self.c33 = Scalar(33., ReducedFunction(domain))
+            self.c44 = Scalar(44., ReducedFunction(domain))
+            self.c66 = Scalar(66., ReducedFunction(domain))
+            self.run_HTI_assembly(domain)
+            self.run_VTI_assembly(domain)
+
+class Test_SpeckleyWaveAssembler2D(SpeckleyWaveAssemblerTestBase):
+    def setUp(self):
+        self.domains = []
+        for order in range(2,11):
+            self.domains.append(Rectangle(order,10,10,l0=100,l1=100,diracTags=["source"],
+                    diracPoints=[(0,0)]))
+        self.wavelet = Ricker(100.)
+        
+    def tearDown(self):
+        del self.domains
+
+class Test_SpeckleyWaveAssembler3D(SpeckleyWaveAssemblerTestBase):
+    def setUp(self):
+        self.domains = []
+        for order in range(2,11):
+            self.domains.append(Brick(order, 4,4,4,
+                    diracTags=["source"], diracPoints=[(0,0,0)]))
+        self.wavelet = Ricker(100.)
+
+    def tearDown(self):
+        del self.domains
+
+
+if __name__ == '__main__':
+    run_tests(__name__, exit_on_failure=True)
+
diff --git a/speckley/test/python/run_diracOnSpeckley.py b/speckley/test/python/run_diracOnSpeckley.py
index cd150f7..8b34aa6 100644
--- a/speckley/test/python/run_diracOnSpeckley.py
+++ b/speckley/test/python/run_diracOnSpeckley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -16,7 +16,7 @@
 
 from __future__ import print_function, division
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/speckley/test/python/run_readWriteOnSpeckley.py b/speckley/test/python/run_readWriteOnSpeckley.py
index e8f2f10..a053d42 100644
--- a/speckley/test/python/run_readWriteOnSpeckley.py
+++ b/speckley/test/python/run_readWriteOnSpeckley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/speckley/test/python/run_specialOnSpeckley.py b/speckley/test/python/run_specialOnSpeckley.py
index 5026aa3..0f95042 100644
--- a/speckley/test/python/run_specialOnSpeckley.py
+++ b/speckley/test/python/run_specialOnSpeckley.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -17,7 +17,7 @@ from __future__ import print_function
 from __future__ import division
 
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
@@ -234,6 +234,43 @@ class Test_Speckley_Assemblers(unittest.TestCase):
                         res, self.TOLERANCE)).format("" if expanded else "un-"))
 
 class Test_Speckley(unittest.TestCase):
+    TOLERANCE = 1e-10
+    def test_Rectangle_ReducedFunction(self):
+        ranks = getMPISizeWorld()
+        for order in range(2, 11):
+            dom = Rectangle(order, 3, 3*ranks, l0=3, l1=3*ranks, d1=ranks)
+            X = dom.getX()
+            redData = interpolate(X, ReducedFunction(dom))
+            data = [(interpolate(redData, ReducedFunction(dom)), "ReducedFunction"),
+                    (interpolate(redData, Function(dom)), "Function"),
+                    (interpolate(redData, ContinuousFunction(dom)), "ContinuousFunction")]
+            for d, fs in data:
+                self.assertLess(inf(d-[0.5]*2), self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != 0"%(fs, order, inf(d-[0.5]*2)))
+                self.assertLess(sup(d[0]+0.5) - 3, self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != 3"%(fs, order, sup(d[0]+0.5)))
+                self.assertLess(sup(d[1]+0.5) - 3*ranks, self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != %g"%(fs, order, sup(d[1]+0.5), 3*ranks))
+
+    def test_Brick_ReducedFunction(self):
+        ranks = getMPISizeWorld()
+        for order in range(2, 11):
+            dom = Brick(order, 3, 3*ranks, 3, l0=3, l1=3*ranks, l2=3, d1=ranks)
+            X = dom.getX()
+            redData = interpolate(X, ReducedFunction(dom))
+            data = [(interpolate(redData, ReducedFunction(dom)), "ReducedFunction"),
+                    (interpolate(redData, Function(dom)), "Function"),
+                    (interpolate(redData, ContinuousFunction(dom)), "ContinuousFunction")]
+            for d, fs in data:
+                self.assertLess(inf(d-[0.5]*3), self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != 0"%(fs, order, inf(d-[0.5]*3)))
+                self.assertLess(sup(d[0]+0.5) - 3, self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != 3"%(fs, order, sup(d[0]+0.5)))
+                self.assertLess(sup(d[1]+0.5) - 3*ranks, self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != %g"%(fs, order, sup(d[1]+0.5), 3*ranks))
+                self.assertLess(sup(d[2]+0.5) - 3, self.TOLERANCE,
+                        "reduced->%s failure with order %d: %g != 3"%(fs, order, sup(d[2]+0.5)))
+
     def test_Rectangle_Function_gradient(self): #expanded and non-expanded
         ranks = getMPISizeWorld()
         for expanded in [True, False]:
diff --git a/tools/escriptconvert/SConscript b/tools/escriptconvert/SConscript
index e9bac1e..17e8fa1 100644
--- a/tools/escriptconvert/SConscript
+++ b/tools/escriptconvert/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/tools/escriptconvert/escriptconvert.cpp b/tools/escriptconvert/escriptconvert.cpp
index fabb907..7bf4cef 100644
--- a/tools/escriptconvert/escriptconvert.cpp
+++ b/tools/escriptconvert/escriptconvert.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/tools/escriptconvert/esdcreate.cpp b/tools/escriptconvert/esdcreate.cpp
index 344db8a..41842b6 100644
--- a/tools/escriptconvert/esdcreate.cpp
+++ b/tools/escriptconvert/esdcreate.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/pasowrap/py_src/SConscript b/tools/overlord/SConscript
similarity index 63%
copy from pasowrap/py_src/SConscript
copy to tools/overlord/SConscript
index 3cc56a8..b5917de 100644
--- a/pasowrap/py_src/SConscript
+++ b/tools/overlord/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,19 +14,13 @@
 #
 ##############################################################################
 
-
 import os
 Import('*')
-
 local_env = env.Clone()
 
-# get the source file names
-sources = Glob('*.py')
-
-# compile
-pyc = local_env.PyCompile(sources)
-
-# install
-py_inst = local_env.Install(local_env['pyinstall']+'/pasowrap', pyc)
-env.Alias('install_pasowrap_py', py_inst)
+if not local_env['IS_WINDOWS']:
+    prog = local_env.Program('escript-overlord', ['overlord.c'])
+    env.Alias('build_overlord', prog)
+    install_overlord = local_env.Install(local_env['bininstall'], prog)
+    env.Alias('install_overlord', install_overlord) #oh no! our freedoms!
 
diff --git a/tools/overlord/overlord.c b/tools/overlord/overlord.c
new file mode 100644
index 0000000..5d63fb7
--- /dev/null
+++ b/tools/overlord/overlord.c
@@ -0,0 +1,70 @@
+/*****************************************************************************
+*
+* Copyright (c) 2003-2015 by The University of Queensland
+* http://www.uq.edu.au
+*
+* Primary Business: Queensland, Australia
+* Licensed under the Open Software License version 3.0
+* http://www.opensource.org/licenses/osl-3.0.php
+*
+* Development until 2012 by Earth Systems Science Computational Center (ESSCC)
+* Development 2012-2013 by School of Earth Sciences
+* Development from 2014 by Centre for Geoscience Computing (GeoComp)
+*
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int main(int argc, char **argv) {
+    int key = 0, port = 0, sfd = 0;
+    FILE *escript = NULL;
+    struct sockaddr_in sa;
+
+    if (argc < 4) {
+        fprintf(stderr, "Missing minimum arguments: %s port key cmd [args]\n",
+                argv[0]);
+        return 1;
+    }
+    key = atoi(argv[2]);
+    port = atoi(argv[1]);
+    
+    
+    sa.sin_family = AF_INET;
+    sa.sin_port = htons(port);
+    sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    memset(sa.sin_zero, '\0', sizeof(sa.sin_zero));
+    
+    sfd = socket(PF_INET, SOCK_STREAM, 0);
+    if (sfd < 0) {
+        perror("overlord socket creation failed");
+        return 1;
+    }
+
+    if (connect(sfd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
+        perror("overlord connect() call failed");
+        return 1;
+    }
+    
+    escript = fdopen(sfd, "w");
+    if (escript == NULL) {
+        perror("overlord failed to open file descriptor for writes");
+        return 1;
+    }
+    if (fwrite(&key, sizeof(int), 1, escript) != 1) {
+        fprintf(stderr, "overlord failed to initialise communication with escript\n");
+        return 1;
+    }
+        
+    fflush(escript);
+    execvp(argv[3], argv+3);
+    perror("overlord exec failed");
+    return 1;
+}
+
diff --git a/tools/testrunner.py b/tools/testrunner.py
index 4fd52ff..bf17f49 100644
--- a/tools/testrunner.py
+++ b/tools/testrunner.py
@@ -1,43 +1,81 @@
 from __future__ import print_function
 import sys
 
+fail_format = """======================================================================
+FAIL: {0} {1}
+----------------------------------------------------------------------
+{2}
+----------------------------------------------------------------------
+"""
+
 def rearrange(string):
     parts = string.split()
     parts = [parts[1][1:-1], parts[0]]
     return ".".join(parts)
 
-def run_tests(modules):
+def rearrange_to_default(string):
+    parts = string.split()
+    print(parts)
+    return ".".join(parts)
+
+def run_tests(modules, exit_on_failure=False):
     skiplist = []
+    faillist = []
     for module in modules:
         if module[-3:] == ".py":
             module = module[:-3]
         m = __import__(module)
-        res = m.run_tests(module)
-        if not res.wasSuccessful():
-            sys.exit(1)
-        skiplist.extend(["%s : %s"%(rearrange(str(i[0])),i[1]) for i in res.skipped])
-    return skiplist
+        res = m.run_tests(module, exit_on_failure=exit_on_failure)
+        skiplist.extend(["%s : %s\n"%(rearrange(str(i[0])),i[1]) for i in res.skipped])
+        faillist.extend([fail_format.format(str(i[0]).split()[0],str(i[0]).split()[1], i[1]) for i in res.failures])
+    return skiplist, faillist
 
 if __name__ == "__main__":
     modules = sys.argv[1:]
     if len(modules) == 0:
         print("%s missing argument, provide module to run tests on"%sys.argv[0])
         sys.exit(1)
-    outputfile = None
-    appendfile = None
-    for n, m in enumerate(modules):
-        if m.startswith("-outputfile="):
+    skipfile = None
+    skipappendfile = None
+    failfile = None
+    failappendfile = None
+    exit = False
+    n = 0
+    while n < len(modules):
+        m = modules[n]
+        if m.startswith("-skipfile="):
+            modules.pop(n)
+            skipfile = m.split("=")[1]
+            continue
+        if m.startswith("-skipappendfile="):
             modules.pop(n)
-            outputfile = m.split("=")[1]
-            break
-        if m.startswith("-appendfile="):
+            skipappendfile = m.split("=")[1]
+            continue
+        if m.startswith("-failfile="):
             modules.pop(n)
-            appendfile = m.split("=")[1]
-            break
-    skipped = run_tests(modules)
-    if outputfile:
-        open(outputfile, "w").writelines("\n".join(skipped))
-    elif appendfile:
-        open(appendfile, "a").writelines("\n".join(skipped))
+            failfile = m.split("=")[1]
+            continue
+        if m.startswith("-failappendfile="):
+            modules.pop(n)
+            failappendfile = m.split("=")[1]
+            continue
+        if m == "-exit":
+            modules.pop(n)
+            exit = True
+            continue
+        n += 1
+
+    skipped, failed = run_tests(modules, exit_on_failure=exit)
+    if skipfile:
+        open(skipfile, "w").writelines("".join(skipped))
+    elif skipappendfile:
+        open(skipappendfile, "a").writelines("".join(skipped))
+    else:
+        print("".join(skipped))
+
+    if failfile:
+        open(failfile, "w").writelines("".join(failed))
+    elif failappendfile:
+        open(failappendfile, "a").writelines("".join(failed))
     else:
-        print("\n".join(skipped))
+        print("".join(failed))
diff --git a/weipa/py_src/SConscript b/weipa/py_src/SConscript
index 5b6d43b..036d4e9 100644
--- a/weipa/py_src/SConscript
+++ b/weipa/py_src/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/weipa/py_src/__init__.py b/weipa/py_src/__init__.py
index 104c578..d50cf1a 100644
--- a/weipa/py_src/__init__.py
+++ b/weipa/py_src/__init__.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/weipa/src/DataVar.cpp b/weipa/src/DataVar.cpp
index 5d8c0e3..c71e999 100644
--- a/weipa/src/DataVar.cpp
+++ b/weipa/src/DataVar.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <weipa/DataVar.h>
 #include <weipa/DomainChunk.h>
 #include <weipa/ElementData.h>
diff --git a/weipa/src/DataVar.h b/weipa/src/DataVar.h
index 8d92332..1a90a6b 100644
--- a/weipa/src/DataVar.h
+++ b/weipa/src/DataVar.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/DomainChunk.h b/weipa/src/DomainChunk.h
index f46586a..f26b2de 100644
--- a/weipa/src/DomainChunk.h
+++ b/weipa/src/DomainChunk.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/ElementData.h b/weipa/src/ElementData.h
index 6fa5ebe..1d9d868 100644
--- a/weipa/src/ElementData.h
+++ b/weipa/src/ElementData.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/EscriptDataset.cpp b/weipa/src/EscriptDataset.cpp
index d045c8f..4fe5b90 100644
--- a/weipa/src/EscriptDataset.cpp
+++ b/weipa/src/EscriptDataset.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <weipa/EscriptDataset.h>
 #include <weipa/DataVar.h>
 #include <weipa/ElementData.h>
diff --git a/weipa/src/EscriptDataset.h b/weipa/src/EscriptDataset.h
index f1e7d10..538e3ef 100644
--- a/weipa/src/EscriptDataset.h
+++ b/weipa/src/EscriptDataset.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/FinleyDomain.cpp b/weipa/src/FinleyDomain.cpp
index ad03355..079a848 100644
--- a/weipa/src/FinleyDomain.cpp
+++ b/weipa/src/FinleyDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <weipa/FinleyDomain.h>
 #include <weipa/FinleyNodes.h>
 #include <weipa/DataVar.h>
diff --git a/weipa/src/FinleyDomain.h b/weipa/src/FinleyDomain.h
index 548712d..7bb2e96 100644
--- a/weipa/src/FinleyDomain.h
+++ b/weipa/src/FinleyDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/FinleyElements.cpp b/weipa/src/FinleyElements.cpp
index fb96036..214afeb 100644
--- a/weipa/src/FinleyElements.cpp
+++ b/weipa/src/FinleyElements.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <weipa/FinleyElements.h>
 #include <weipa/NodeData.h>
 
diff --git a/weipa/src/FinleyElements.h b/weipa/src/FinleyElements.h
index fbb5c03..db199f9 100644
--- a/weipa/src/FinleyElements.h
+++ b/weipa/src/FinleyElements.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/FinleyNodes.cpp b/weipa/src/FinleyNodes.cpp
index 2498826..e309b49 100644
--- a/weipa/src/FinleyNodes.cpp
+++ b/weipa/src/FinleyNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/FinleyNodes.h>
 
 #ifndef VISIT_PLUGIN
diff --git a/weipa/src/FinleyNodes.h b/weipa/src/FinleyNodes.h
index 2a4728a..3c3c5e7 100644
--- a/weipa/src/FinleyNodes.h
+++ b/weipa/src/FinleyNodes.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/NodeData.h b/weipa/src/NodeData.h
index f1cadbb..4ce17f1 100644
--- a/weipa/src/NodeData.h
+++ b/weipa/src/NodeData.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/RipleyDomain.cpp b/weipa/src/RipleyDomain.cpp
index 46f8d45..130e039 100644
--- a/weipa/src/RipleyDomain.cpp
+++ b/weipa/src/RipleyDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/RipleyDomain.h>
 #include <weipa/RipleyNodes.h>
 #include <weipa/DataVar.h>
diff --git a/weipa/src/RipleyDomain.h b/weipa/src/RipleyDomain.h
index 0d933cd..0c96276 100644
--- a/weipa/src/RipleyDomain.h
+++ b/weipa/src/RipleyDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/RipleyElements.cpp b/weipa/src/RipleyElements.cpp
index 464ac0e..3fac39e 100644
--- a/weipa/src/RipleyElements.cpp
+++ b/weipa/src/RipleyElements.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/RipleyElements.h>
 #include <weipa/NodeData.h>
 
@@ -73,7 +76,6 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
 #ifndef VISIT_PLUGIN
     const pair<int,dim_t> shape = dom->getDataShape(fsType);
     const dim_t* faces = dom->getNumFacesPerBoundary();
-    const int* NS = dom->getNumSubdivisionsPerDim();
 
     numElements = shape.second;
 
@@ -90,7 +92,7 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                 type = ZONETYPE_HEX;
                 break;
         }
-        owner.assign(numElements, dom->getMPIRank());
+        owner = dom->getOwnerVector(fsType);
 
         const dim_t* iPtr = dom->borrowSampleReferenceIDs(fsType);
         ID.assign(iPtr, iPtr+numElements);
@@ -103,17 +105,6 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
         nodes.clear();
         if (dom->getDim() == 2) {
             if (fsType==ripley::Elements) {
-                if (faces[0]==0) {
-                    owner[0]=(faces[2]==0 ? dom->getMPIRank()-NS[0]-1
-                            : dom->getMPIRank()-1);
-                    for (dim_t i=1; i<NE[1]; i++)
-                        owner[i*NE[0]]=dom->getMPIRank()-1;
-                }
-                if (faces[2]==0) {
-                    const int first=(faces[0]==0 ? 1 : 0);
-                    for (dim_t i=first; i<NE[0]; i++)
-                        owner[i]=dom->getMPIRank()-NS[0];
-                }
                 int id=0;
                 for (dim_t i=0; i<numElements; i++) {
                     nodes.push_back(id);
@@ -125,19 +116,6 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                         id++;
                 }
             } else if (fsType==ripley::FaceElements) {
-                if (faces[0]==0) {
-                    if (faces[2]>0)
-                        owner[faces[1]]=dom->getMPIRank()-1;
-                    if (faces[3]>0)
-                        owner[faces[1]+faces[2]]=dom->getMPIRank()-1;
-                }
-                if (faces[2]==0) {
-                    if (faces[0]>0)
-                        owner[0]=dom->getMPIRank()-NS[0];
-                    if (faces[1]>0)
-                        owner[faces[0]]=dom->getMPIRank()-NS[0];
-                }
-
                 int id=0;
                 for (dim_t i=0; i<faces[0]; i++) {
                     nodes.push_back(id);
@@ -165,32 +143,6 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
             }
         } else {
             if (fsType==ripley::Elements) {
-                // ownership is not entirely correct but that is not critical.
-                // fix when there is time.
-                if (faces[1]==0) {
-                    for (dim_t k2=0; k2<NE[2]; k2++) {
-                        for (dim_t k1=0; k1<NE[1]; k1++) {
-                            const dim_t e=k2*NE[0]*NE[1]+(k1+1)*NE[0]-1;
-                            owner[e]=dom->getMPIRank()+1;
-                        }
-                    }
-                }
-                if (faces[3]==0) {
-                    for (dim_t k2=0; k2<NE[2]; k2++) {
-                        for (dim_t k0=0; k0<NE[0]; k0++) {
-                            const dim_t e=(k2+1)*NE[0]*NE[1]-NE[0]+k0;
-                            owner[e]=dom->getMPIRank()+NS[0];
-                        }
-                    }
-                }
-                if (faces[5]==0) {
-                    for (dim_t k1=0; k1<NE[1]; k1++) {
-                        for (dim_t k0=0; k0<NE[0]; k0++) {
-                            const dim_t e=k1*NE[0]+k0+NE[0]*NE[1]*(NE[2]-1);
-                            owner[e]=dom->getMPIRank()+NS[0]*NS[1];
-                        }
-                    }
-                }
                 int id=0;
                 for (dim_t i=0; i<numElements; i++) {
                     nodes.push_back(id);
@@ -209,19 +161,8 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                         id+=NN[0];
                 }
             } else if (fsType==ripley::FaceElements) {
-                // ownership is not entirely correct but that is not critical.
-                // fix when there is time.
                 const dim_t* NE = dom->getNumElementsPerDim();
-                int offset=0;
                 if (faces[0]>0) {
-                    if (faces[3]==0) {
-                        for (dim_t k2=0; k2<NE[2]; k2++)
-                            owner[(k2+1)*NE[1]-1]=dom->getMPIRank()+NS[0];
-                    }
-                    if (faces[5]==0) {
-                        for (dim_t k1=0; k1<NE[1]; k1++)
-                            owner[NE[1]*(NE[2]-1)+k1]=dom->getMPIRank()+NS[0]*NS[1];
-                    }
                     for (dim_t k2=0; k2<NE[2]; k2++) {
                         for (dim_t k1=0; k1<NE[1]; k1++) {
                             const dim_t first=k2*NN[0]*NN[1]+k1*NN[0];
@@ -231,17 +172,8 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                             nodes.push_back(first+NN[0]*(NN[1]+1));
                         }
                     }
-                    offset+=faces[0];
                 }
                 if (faces[1]>0) {
-                    if (faces[3]==0) {
-                        for (dim_t k2=0; k2<NE[2]; k2++)
-                            owner[offset+(k2+1)*NE[1]-1]=dom->getMPIRank()+NS[0]+1;
-                    }
-                    if (faces[5]==0) {
-                        for (dim_t k1=0; k1<NE[1]; k1++)
-                            owner[offset+NE[1]*(NE[2]-1)+k1]=dom->getMPIRank()+NS[0]*NS[1]+1;
-                    }
                     for (dim_t k2=0; k2<NE[2]; k2++) {
                         for (dim_t k1=0; k1<NE[1]; k1++) {
                             const dim_t first=k2*NN[0]*NN[1]+(k1+1)*NN[0]-1;
@@ -251,17 +183,8 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                             nodes.push_back(first+NN[0]*(NN[1]+1));
                         }
                     }
-                    offset+=faces[1];
                 }
                 if (faces[2]>0) {
-                    if (faces[1]==0) {
-                        for (dim_t k2=0; k2<NE[2]; k2++)
-                            owner[offset+(k2+1)*NE[0]-1]=dom->getMPIRank()+1;
-                    }
-                    if (faces[5]==0) {
-                        for (dim_t k0=0; k0<NE[0]; k0++)
-                            owner[offset+NE[0]*(NE[2]-1)+k0]=dom->getMPIRank()+NS[0]*NS[1];
-                    }
                     for (dim_t k2=0; k2<NE[2]; k2++) {
                         for (dim_t k0=0; k0<NE[0]; k0++) {
                             const dim_t first=k2*NN[0]*NN[1]+k0;
@@ -271,17 +194,8 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                             nodes.push_back(first+1+NN[0]*NN[1]);
                         }
                     }
-                    offset+=faces[2];
                 }
                 if (faces[3]>0) {
-                    if (faces[1]==0) {
-                        for (dim_t k2=0; k2<NE[2]; k2++)
-                            owner[offset+(k2+1)*NE[0]-1]=dom->getMPIRank()+NS[0]+1;
-                    }
-                    if (faces[5]==0) {
-                        for (dim_t k0=0; k0<NE[0]; k0++)
-                            owner[offset+NE[0]*(NE[2]-1)+k0]=dom->getMPIRank()+NS[0]*(NS[1]+1);
-                    }
                     for (dim_t k2=0; k2<NE[2]; k2++) {
                         for (dim_t k0=0; k0<NE[0]; k0++) {
                             const dim_t first=(k2+1)*NN[0]*NN[1]-NN[0]+k0;
@@ -291,17 +205,8 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                             nodes.push_back(first+1+NN[0]*NN[1]);
                         }
                     }
-                    offset+=faces[3];
                 }
                 if (faces[4]>0) {
-                    if (faces[1]==0) {
-                        for (dim_t k1=0; k1<NE[1]; k1++)
-                            owner[offset+(k1+1)*NE[0]-1]=dom->getMPIRank()+1;
-                    }
-                    if (faces[3]==0) {
-                        for (dim_t k0=0; k0<NE[0]; k0++)
-                            owner[offset+NE[0]*(NE[1]-1)+k0]=dom->getMPIRank()+NS[0];
-                    }
                     for (dim_t k1=0; k1<NE[1]; k1++) {
                         for (dim_t k0=0; k0<NE[0]; k0++) {
                             const dim_t first=k1*NN[0]+k0;
@@ -311,17 +216,8 @@ bool RipleyElements::initFromRipley(const ripley::RipleyDomain* dom, int fsType)
                             nodes.push_back(first+NN[0]);
                         }
                     }
-                    offset+=faces[4];
                 }
                 if (faces[5]>0) {
-                    if (faces[1]==0) {
-                        for (dim_t k1=0; k1<NE[1]; k1++)
-                            owner[offset+(k1+1)*NE[0]-1]=dom->getMPIRank()+NS[0]*NS[1]+1;
-                    }
-                    if (faces[3]==0) {
-                        for (dim_t k0=0; k0<NE[0]; k0++)
-                            owner[offset+NE[0]*(NE[1]-1)+k0]=dom->getMPIRank()+NS[0]*(NS[1]+1);
-                    }
                     for (dim_t k1=0; k1<NE[1]; k1++) {
                         for (dim_t k0=0; k0<NE[0]; k0++) {
                             const dim_t first=NN[0]*NN[1]*(NN[2]-1)+k1*NN[0]+k0;
@@ -386,7 +282,8 @@ void RipleyElements::reorderArray(IntVec& v, const IntVec& idx,
     } else {
         for (idxIt=idx.begin(); idxIt!=idx.end(); idxIt++) {
             int i = *idxIt;
-            copy(&v[i*elementsPerIndex], &v[(i+1)*elementsPerIndex], arrIt);
+            int* start = &v[i*elementsPerIndex];
+            copy(start, start+elementsPerIndex, arrIt);
             arrIt += elementsPerIndex;
         }
     }
diff --git a/weipa/src/RipleyElements.h b/weipa/src/RipleyElements.h
index 995abf1..de1cab6 100644
--- a/weipa/src/RipleyElements.h
+++ b/weipa/src/RipleyElements.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/RipleyNodes.cpp b/weipa/src/RipleyNodes.cpp
index 3b210d2..65abcea 100644
--- a/weipa/src/RipleyNodes.cpp
+++ b/weipa/src/RipleyNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/RipleyNodes.h>
 
 #ifndef VISIT_PLUGIN
diff --git a/weipa/src/RipleyNodes.h b/weipa/src/RipleyNodes.h
index b2d83ee..9706750 100644
--- a/weipa/src/RipleyNodes.h
+++ b/weipa/src/RipleyNodes.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/SConscript b/weipa/src/SConscript
index f2955c1..37b9ac0 100644
--- a/weipa/src/SConscript
+++ b/weipa/src/SConscript
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/weipa/src/SpeckleyDomain.cpp b/weipa/src/SpeckleyDomain.cpp
index c46bd9f..770a00c 100644
--- a/weipa/src/SpeckleyDomain.cpp
+++ b/weipa/src/SpeckleyDomain.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/SpeckleyDomain.h>
 #include <weipa/SpeckleyNodes.h>
 #include <weipa/DataVar.h>
@@ -109,11 +112,6 @@ ElementData_ptr SpeckleyDomain::getElementsForFunctionSpace(int fsCode) const
             result = cells;
             break;
 
-//        case speckley::ReducedFaceElements:
-//        case speckley::FaceElements:
-//            result = faces;
-//            break;
-
         default: {
             cerr << "Unsupported function space type " << fsCode
                 << "!" << endl;
diff --git a/weipa/src/SpeckleyDomain.h b/weipa/src/SpeckleyDomain.h
index 19a9218..e7274a9 100644
--- a/weipa/src/SpeckleyDomain.h
+++ b/weipa/src/SpeckleyDomain.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/SpeckleyElements.cpp b/weipa/src/SpeckleyElements.cpp
index ff6e2c5..f9a3df6 100644
--- a/weipa/src/SpeckleyElements.cpp
+++ b/weipa/src/SpeckleyElements.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/SpeckleyElements.h>
 #include <weipa/NodeData.h>
 
@@ -84,16 +87,23 @@ bool SpeckleyElements::initFromSpeckley(const speckley::SpeckleyDomain* dom, int
     const int order = dom->getOrder();
 
     numElements = shape.second*order*order;
+    int nodesPerOrigElement = order*order;
     if (numElements > 0) {
         nodesPerElement = 4;
         if (dom->getDim() == 3) {
             nodesPerElement = 8;
             numElements *= order;
+            nodesPerOrigElement *= order;
         }
         owner.assign(numElements, dom->getMPIRank());
 
         const dim_t* iPtr = dom->borrowSampleReferenceIDs(fsType);
-        ID.assign(iPtr, iPtr+shape.second);
+        ID.resize(numElements);
+        for (int i = 0; i < shape.second; i++) {
+            for (int n = 0; n < nodesPerOrigElement; n++) {
+                ID[i*n + n] = iPtr[i];
+            }
+        }
 
         const dim_t* NE = dom->getNumElementsPerDim();
         const dim_t* NN = dom->getNumNodesPerDim();
diff --git a/weipa/src/SpeckleyElements.h b/weipa/src/SpeckleyElements.h
index 9fce644..02f45e8 100644
--- a/weipa/src/SpeckleyElements.h
+++ b/weipa/src/SpeckleyElements.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/SpeckleyNodes.cpp b/weipa/src/SpeckleyNodes.cpp
index 3dcbc34..355af08 100644
--- a/weipa/src/SpeckleyNodes.cpp
+++ b/weipa/src/SpeckleyNodes.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/SpeckleyNodes.h>
 
 #ifndef VISIT_PLUGIN
diff --git a/weipa/src/SpeckleyNodes.h b/weipa/src/SpeckleyNodes.h
index 7d6c08a..954e159 100644
--- a/weipa/src/SpeckleyNodes.h
+++ b/weipa/src/SpeckleyNodes.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/VisItControl.cpp b/weipa/src/VisItControl.cpp
index fdbc0f4..80d0b38 100644
--- a/weipa/src/VisItControl.cpp
+++ b/weipa/src/VisItControl.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include <weipa/VisItControl.h>
 #include <weipa/EscriptDataset.h>
 
diff --git a/weipa/src/VisItControl.h b/weipa/src/VisItControl.h
index 6e245a9..75e1600 100644
--- a/weipa/src/VisItControl.h
+++ b/weipa/src/VisItControl.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/VisItData.cpp b/weipa/src/VisItData.cpp
index a509a99..59aa793 100644
--- a/weipa/src/VisItData.cpp
+++ b/weipa/src/VisItData.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <weipa/VisItData.h>
 #include <weipa/DataVar.h>
 #include <weipa/ElementData.h>
diff --git a/weipa/src/VisItData.h b/weipa/src/VisItData.h
index 7b86685..f46d916 100644
--- a/weipa/src/VisItData.h
+++ b/weipa/src/VisItData.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/weipa.h b/weipa/src/weipa.h
index d1365a7..11374a6 100644
--- a/weipa/src/weipa.h
+++ b/weipa/src/weipa.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/src/weipacpp.cpp b/weipa/src/weipacpp.cpp
index 5ca6e43..99bd4a9 100644
--- a/weipa/src/weipacpp.cpp
+++ b/weipa/src/weipacpp.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 
 #include <escript/Data.h>
 
diff --git a/weipa/test/EscriptDatasetTestCase.cpp b/weipa/test/EscriptDatasetTestCase.cpp
index 2c26e08..8758cb1 100644
--- a/weipa/test/EscriptDatasetTestCase.cpp
+++ b/weipa/test/EscriptDatasetTestCase.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,9 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
 #include "EscriptDatasetTestCase.h"
 #include <escript/DataFactory.h>
 #include <escript/FunctionSpaceFactory.h>
@@ -90,6 +93,7 @@ void EscriptDatasetTestCase::testDudley()
 {
     esysUtils::JMPI info=esysUtils::makeInfo(MPI_COMM_WORLD);
     Domain_ptr dom(dudley::brick(info));
+    cout << "Running Dudley tests..." << endl;
     runDomainTests(dom);
 }
 #endif
@@ -99,6 +103,7 @@ void EscriptDatasetTestCase::testFinley()
 {
     esysUtils::JMPI info=esysUtils::makeInfo(MPI_COMM_WORLD);
     Domain_ptr dom(finley::brick(info));
+    cout << "Running Finley tests..." << endl;
     runDomainTests(dom);
 }
 #endif
@@ -107,6 +112,7 @@ void EscriptDatasetTestCase::testFinley()
 void EscriptDatasetTestCase::testRipley()
 {
     Domain_ptr dom(new ripley::Brick(5,4,3, 0,0,0, 1,1,1));
+    cout << "Running Ripley tests..." << endl;
     runDomainTests(dom);
 }
 #endif
@@ -116,6 +122,7 @@ void EscriptDatasetTestCase::testSpeckley()
 {
     for (int i = 2; i < 11; i++) {
         Domain_ptr dom(new speckley::Brick(i, 5,4,3, 0,0,0, 1,1,1));
+        cout << "Running Speckley order " << i << " tests..." << endl;
         runDomainTests(dom);
     }
 }
diff --git a/weipa/test/EscriptDatasetTestCase.h b/weipa/test/EscriptDatasetTestCase.h
index a343245..1afd3c5 100644
--- a/weipa/test/EscriptDatasetTestCase.h
+++ b/weipa/test/EscriptDatasetTestCase.h
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
diff --git a/weipa/test/SConscript b/weipa/test/SConscript
index 6fa59e6..713789f 100644
--- a/weipa/test/SConscript
+++ b/weipa/test/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
diff --git a/weipa/test/python/SConscript b/weipa/test/python/SConscript
index 018687d..8688653 100644
--- a/weipa/test/python/SConscript
+++ b/weipa/test/python/SConscript
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -46,6 +46,8 @@ env.Alias('py_tests', [splitext(x)[0]+'.passed' for x in testruns])
 # run all tests
 program = local_env.RunPyUnitTest(alltestruns)
 Depends(program, 'build_py_tests')
+if env['usempi']:
+    Depends(program, env['prefix']+"/lib/pythonMPI")
 
 # add a group of tests
 from grouptest import *
diff --git a/weipa/test/python/run_savesilo_tests.py b/weipa/test/python/run_savesilo_tests.py
index 89c849a..dadb8c9 100644
--- a/weipa/test/python/run_savesilo_tests.py
+++ b/weipa/test/python/run_savesilo_tests.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/weipa/test/python/run_savevtk_tests.py b/weipa/test/python/run_savevtk_tests.py
index 07f71b5..3bcd9c8 100644
--- a/weipa/test/python/run_savevtk_tests.py
+++ b/weipa/test/python/run_savevtk_tests.py
@@ -1,7 +1,7 @@
 
 ##############################################################################
 #
-# Copyright (c) 2003-2014 by University of Queensland
+# Copyright (c) 2003-2015 by The University of Queensland
 # http://www.uq.edu.au
 #
 # Primary Business: Queensland, Australia
@@ -14,7 +14,7 @@
 #
 ##############################################################################
 
-__copyright__="""Copyright (c) 2003-2014 by University of Queensland
+__copyright__="""Copyright (c) 2003-2015 by The University of Queensland
 http://www.uq.edu.au
 Primary Business: Queensland, Australia"""
 __license__="""Licensed under the Open Software License version 3.0
diff --git a/weipa/test/weipa_UnitTest.cpp b/weipa/test/weipa_UnitTest.cpp
index 871e841..9acea95 100644
--- a/weipa/test/weipa_UnitTest.cpp
+++ b/weipa/test/weipa_UnitTest.cpp
@@ -1,7 +1,7 @@
 
 /*****************************************************************************
 *
-* Copyright (c) 2003-2014 by University of Queensland
+* Copyright (c) 2003-2015 by The University of Queensland
 * http://www.uq.edu.au
 *
 * Primary Business: Queensland, Australia
@@ -14,6 +14,10 @@
 *
 *****************************************************************************/
 
+#define ESNEEDPYTHON
+#include "esysUtils/first.h"
+
+
 #include <iostream>
 
 #include "EscriptDatasetTestCase.h"

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



More information about the debian-science-commits mailing list