[med-svn] [plastimatch] 02/06: New upstream version 1.6.6+dfsg.1

Greg Sharp gregsharp-guest at moszumanska.debian.org
Wed Oct 11 17:24:38 UTC 2017


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

gregsharp-guest pushed a commit to branch master
in repository plastimatch.

commit 9a47d41b87aab60a17701754f66f3da273a27d0a
Author: Gregory C. Sharp <gregsharp.geo at yahoo.com>
Date:   Wed Oct 11 12:47:19 2017 -0400

    New upstream version 1.6.6+dfsg.1
---
 CMakeLists.txt                                     |   20 +-
 INSTALL.TXT                                        |    0
 LICENSE.TXT                                        |    0
 README.TXT                                         |   37 +-
 Testing/CMakeLists.txt                             |  180 ++--
 Testing/Data/plm-bsp-dmap-k.txt                    |   15 +
 Testing/Data/plm-bsp-sm-multi-a.txt                |   12 +-
 Testing/Data/plm-reg-align-center.txt              |    9 +-
 Testing/Data/plm-reg-gw-a.txt                      |    8 +
 Testing/Data/plm-reg-multi-a.txt                   |    1 -
 Testing/Data/proton-dose-1.txt                     |    0
 .../{proton-dose-5g.txt => proton-dose-5d.txt}     |   36 +-
 .../Data/{proton-dose-1.txt => proton-dose-7a.txt} |   42 +-
 cmake/FindCUDA_wrap.cmake                          |    9 +
 cmake/FindKaze.cmake                               |   35 +
 cmake/FindPaxscan.cmake                            |    2 +-
 doc/NOTES.TXT                                      |  396 +++++++-
 doc/STYLE_GUIDE_2.TXT                              |   35 +
 doc/man/drr.1                                      |    2 +-
 doc/man/fdk.1                                      |    6 +-
 doc/man/landmark_warp.1                            |    2 +-
 doc/man/plastimatch.1                              |   32 +-
 run_lcov.sh                                        |    7 -
 src/CMakeLists.txt                                 |    5 +
 src/plastimatch/CHANGELOG.TXT                      |   10 +
 src/plastimatch/CMakeLists.txt                     |    5 +-
 src/plastimatch/COPYRIGHT.TXT                      |    0
 src/plastimatch/Doxyfile.in                        |    0
 src/plastimatch/base/CMakeLists.txt                |    3 +
 src/plastimatch/base/aperture.cxx                  |   82 +-
 src/plastimatch/base/aperture.h                    |   11 +-
 src/plastimatch/base/bspline_xform.cxx             |   33 +-
 src/plastimatch/base/bspline_xform.h               |   10 +
 src/plastimatch/base/dcmtk_config.h                |    0
 src/plastimatch/base/dcmtk_file.cxx                |    8 +-
 src/plastimatch/base/dcmtk_file.h                  |    0
 src/plastimatch/base/dcmtk_image.cxx               |   11 +-
 src/plastimatch/base/dcmtk_metadata.cxx            |    0
 src/plastimatch/base/dcmtk_metadata.h              |    0
 src/plastimatch/base/dcmtk_module.cxx              |   13 +-
 src/plastimatch/base/dcmtk_rdd.cxx                 |    0
 src/plastimatch/base/dcmtk_rdd.h                   |    0
 src/plastimatch/base/dcmtk_rt_study.cxx            |    0
 src/plastimatch/base/dcmtk_rt_study.h              |    1 +
 src/plastimatch/base/dcmtk_rtdose.cxx              |    5 +-
 src/plastimatch/base/dcmtk_rtplan.cxx              |  152 ++-
 src/plastimatch/base/dcmtk_rtss.cxx                |    7 +-
 src/plastimatch/base/dcmtk_rtss.h                  |    0
 src/plastimatch/base/dcmtk_series.cxx              |    0
 src/plastimatch/base/dcmtk_series.h                |    2 +-
 src/plastimatch/base/dcmtk_slice_data.h            |    0
 src/plastimatch/base/dcmtk_uid.cxx                 |    0
 src/plastimatch/base/dcmtk_uid.h                   |    0
 src/plastimatch/base/dcmtk_util.cxx                |    6 +
 src/plastimatch/base/dcmtk_util.h                  |    2 +
 src/plastimatch/base/dicom.dic                     |    0
 src/plastimatch/base/dicom_util.cxx                |    0
 src/plastimatch/base/dicom_util.h                  |    0
 src/plastimatch/base/direction_cosines.cxx         |    0
 src/plastimatch/base/direction_cosines.h           |    0
 src/plastimatch/base/direction_matrices.cxx        |    0
 src/plastimatch/base/direction_matrices.h          |    0
 src/plastimatch/base/float_pair_list.cxx           |    0
 src/plastimatch/base/float_pair_list.h             |    0
 src/plastimatch/base/gaussian.cxx                  |    1 -
 src/plastimatch/base/gaussian.h                    |    0
 src/plastimatch/base/gdcm1_dose.cxx                |    0
 src/plastimatch/base/gdcm1_dose.h                  |    0
 src/plastimatch/base/gdcm1_file.cxx                |    0
 src/plastimatch/base/gdcm1_file.h                  |    0
 src/plastimatch/base/gdcm1_rdd.cxx                 |    0
 src/plastimatch/base/gdcm1_rdd.h                   |    0
 src/plastimatch/base/gdcm1_rtss.cxx                |    0
 src/plastimatch/base/gdcm1_rtss.h                  |    0
 src/plastimatch/base/gdcm1_series.cxx              |    0
 src/plastimatch/base/gdcm1_series.h                |    0
 src/plastimatch/base/gdcm1_series_helper_2.cxx     |    0
 src/plastimatch/base/gdcm1_series_helper_2.h       |    0
 src/plastimatch/base/gdcm1_util.cxx                |    0
 src/plastimatch/base/gdcm1_util.h                  |    0
 src/plastimatch/base/gdcm2_util.cxx                |    0
 src/plastimatch/base/gdcm2_util.h                  |    0
 src/plastimatch/base/hnd_io.cxx                    |    2 +-
 src/plastimatch/base/interpolate.cxx               |   76 +-
 src/plastimatch/base/interpolate.h                 |   23 +-
 src/plastimatch/base/itkClampCastImageFilter.h     |    0
 src/plastimatch/base/itkClampCastImageFilter.txx   |    0
 src/plastimatch/base/itk_bbox.cxx                  |   50 +
 src/plastimatch/base/{dcmtk_uid.h => itk_bbox.h}   |    9 +-
 src/plastimatch/base/itk_dicom_load.cxx            |    0
 src/plastimatch/base/itk_dicom_load.h              |    0
 src/plastimatch/base/itk_dicom_save.cxx            |    0
 src/plastimatch/base/itk_dicom_save.h              |    0
 src/plastimatch/base/itk_directions.cxx            |    0
 src/plastimatch/base/itk_directions.h              |    0
 src/plastimatch/base/itk_image_clone.cxx           |   22 +-
 src/plastimatch/base/itk_image_clone.h             |    2 +
 src/plastimatch/base/itk_image_load_char.cxx       |    0
 src/plastimatch/base/itk_image_load_double.cxx     |    0
 src/plastimatch/base/itk_image_type.h              |    0
 src/plastimatch/base/itk_metadata.cxx              |    0
 src/plastimatch/base/itk_metadata.h                |    0
 src/plastimatch/base/itk_pointset.cxx              |    0
 src/plastimatch/base/itk_pointset.h                |    0
 src/plastimatch/base/parameter_parser.cxx          |   42 +-
 src/plastimatch/base/parameter_parser.h            |   12 +
 src/plastimatch/base/plm_file_format.cxx           |    0
 src/plastimatch/base/plm_file_format.h             |    0
 src/plastimatch/base/plm_image_header.cxx          |   13 +
 src/plastimatch/base/plm_image_header.h            |    2 +
 src/plastimatch/base/plm_image_type.cxx            |    0
 src/plastimatch/base/proj_image.cxx                |    6 +-
 src/plastimatch/base/proj_matrix.cxx               |   21 +-
 src/plastimatch/base/proj_matrix.h                 |   14 +-
 src/plastimatch/base/proj_volume.cxx               |   51 +-
 src/plastimatch/base/proj_volume.h                 |   23 +-
 src/plastimatch/base/pwlut.cxx                     |    0
 src/plastimatch/base/pwlut.h                       |    0
 src/plastimatch/base/ray_trace.h                   |    7 +-
 src/plastimatch/base/ray_trace_uniform.cxx         |    6 -
 src/plastimatch/base/rpl_volume.cxx                | 1051 ++++++--------------
 src/plastimatch/base/rpl_volume.h                  |   58 +-
 src/plastimatch/base/rpl_volume_lut.cxx            |  163 +++
 src/plastimatch/base/rpl_volume_lut.h              |   37 +
 src/plastimatch/base/rt_study_metadata.cxx         |  109 +-
 src/plastimatch/base/rt_study_metadata.h           |   24 +-
 src/plastimatch/base/rt_study_p.h                  |    0
 src/plastimatch/base/rtplan.cxx                    |   11 +
 src/plastimatch/base/rtplan.h                      |   16 +
 src/plastimatch/base/rtplan_beam.cxx               |   43 +-
 src/plastimatch/base/rtplan_beam.h                 |   30 +-
 src/plastimatch/base/rtplan_control_pt.h           |    0
 src/plastimatch/base/rtss.cxx                      |   16 +-
 src/plastimatch/base/slice_list.cxx                |    0
 src/plastimatch/base/slice_list.h                  |    0
 src/plastimatch/base/thumbnail.cxx                 |    0
 src/plastimatch/base/thumbnail.h                   |    0
 src/plastimatch/base/vf.cxx                        |    0
 src/plastimatch/base/vf_convolve.cxx               |    0
 src/plastimatch/base/volume.cxx                    |    2 +-
 src/plastimatch/base/volume.h                      |   24 +-
 src/plastimatch/base/volume_boundary_behavior.h    |   24 +
 src/plastimatch/base/volume_fill.cxx               |    0
 src/plastimatch/base/volume_fill.h                 |    0
 src/plastimatch/base/volume_grad.cxx               |    8 +-
 src/plastimatch/base/volume_grad.h                 |    4 +-
 src/plastimatch/base/volume_header.cxx             |   11 +
 src/plastimatch/base/volume_header.h               |    2 +
 src/plastimatch/base/volume_limit.h                |    0
 src/plastimatch/base/volume_macros.h               |    0
 src/plastimatch/base/volume_resample.cxx           |    0
 src/plastimatch/base/volume_stats.cxx              |    0
 src/plastimatch/base/volume_stats.h                |    0
 src/plastimatch/base/xform_convert.cxx             |    0
 src/plastimatch/base/xform_convert.h               |    0
 src/plastimatch/base/xform_legacy.cxx              |    0
 src/plastimatch/base/xform_legacy.h                |    0
 src/plastimatch/base/xio_ct.cxx                    |    0
 src/plastimatch/base/xio_ct_transform.cxx          |    0
 src/plastimatch/base/xio_ct_transform.h            |    0
 src/plastimatch/base/xio_demographic.cxx           |    0
 src/plastimatch/base/xio_demographic.h             |    0
 src/plastimatch/base/xio_dir.cxx                   |    0
 src/plastimatch/base/xio_patient.cxx               |    0
 src/plastimatch/base/xio_patient.h                 |    0
 src/plastimatch/base/xio_structures.cxx            |    0
 src/plastimatch/cli/CMakeLists.txt                 |    5 +-
 src/plastimatch/cli/pcmd_add.h                     |    0
 src/plastimatch/cli/pcmd_adjust.cxx                |    0
 src/plastimatch/cli/pcmd_adjust.h                  |    0
 src/plastimatch/cli/pcmd_autolabel.cxx             |    0
 src/plastimatch/cli/pcmd_autolabel.h               |    0
 src/plastimatch/cli/pcmd_autolabel_train.cxx       |    0
 src/plastimatch/cli/pcmd_autolabel_train.h         |    0
 src/plastimatch/cli/pcmd_bbox.cxx                  |  130 +++
 src/plastimatch/cli/{pcmd_drr.h => pcmd_bbox.h}    |    6 +-
 src/plastimatch/cli/pcmd_benchmark.cxx             |    0
 src/plastimatch/cli/pcmd_benchmark.h               |    0
 src/plastimatch/cli/pcmd_boundary.cxx              |    0
 src/plastimatch/cli/pcmd_boundary.h                |    0
 src/plastimatch/cli/pcmd_compare.cxx               |    0
 src/plastimatch/cli/pcmd_compare.h                 |    0
 src/plastimatch/cli/pcmd_compose.cxx               |    0
 src/plastimatch/cli/pcmd_compose.h                 |    0
 src/plastimatch/cli/pcmd_crop.cxx                  |    0
 src/plastimatch/cli/pcmd_crop.h                    |    0
 src/plastimatch/cli/pcmd_dice.cxx                  |    0
 src/plastimatch/cli/pcmd_dice.h                    |    0
 src/plastimatch/cli/pcmd_diff.cxx                  |    0
 src/plastimatch/cli/pcmd_diff.h                    |    0
 src/plastimatch/cli/pcmd_dmap.cxx                  |    0
 src/plastimatch/cli/pcmd_dmap.h                    |    0
 src/plastimatch/cli/pcmd_dose.cxx                  |   33 +
 src/plastimatch/cli/{pcmd_add.h => pcmd_dose.h}    |    6 +-
 src/plastimatch/cli/pcmd_drr.cxx                   |    0
 src/plastimatch/cli/pcmd_drr.h                     |    0
 src/plastimatch/cli/pcmd_dvh.cxx                   |    0
 src/plastimatch/cli/pcmd_dvh.h                     |    0
 src/plastimatch/cli/pcmd_filter.cxx                |    0
 src/plastimatch/cli/pcmd_filter.h                  |    0
 src/plastimatch/cli/pcmd_gamma.cxx                 |    0
 src/plastimatch/cli/pcmd_gamma.h                   |    0
 src/plastimatch/cli/pcmd_header.cxx                |    0
 src/plastimatch/cli/pcmd_header.h                  |    0
 src/plastimatch/cli/pcmd_mabs.cxx                  |    0
 src/plastimatch/cli/pcmd_mabs.h                    |    0
 src/plastimatch/cli/pcmd_mask.cxx                  |    0
 src/plastimatch/cli/pcmd_mask.h                    |    0
 src/plastimatch/cli/pcmd_probe.h                   |    0
 src/plastimatch/cli/pcmd_register.cxx              |    9 +-
 src/plastimatch/cli/pcmd_scale.h                   |    0
 src/plastimatch/cli/pcmd_segment.cxx               |    0
 src/plastimatch/cli/pcmd_segment.h                 |    0
 src/plastimatch/cli/pcmd_sift.h                    |    0
 src/plastimatch/cli/pcmd_stats.cxx                 |    0
 src/plastimatch/cli/pcmd_stats.h                   |    0
 src/plastimatch/cli/pcmd_synth.cxx                 |    0
 src/plastimatch/cli/pcmd_synth.h                   |    0
 src/plastimatch/cli/pcmd_synth_vf.cxx              |    0
 src/plastimatch/cli/pcmd_synth_vf.h                |    0
 src/plastimatch/cli/pcmd_threshold.cxx             |    0
 src/plastimatch/cli/pcmd_threshold.h               |    0
 src/plastimatch/cli/pcmd_thumbnail.cxx             |    0
 src/plastimatch/cli/pcmd_thumbnail.h               |    0
 src/plastimatch/cli/pcmd_union.h                   |    0
 .../vf_invert_main.cxx => cli/pcmd_vf_invert.cxx}  |   51 +-
 .../cli/{pcmd_add.h => pcmd_vf_invert.h}           |    6 +-
 src/plastimatch/cli/pcmd_warp.cxx                  |    0
 src/plastimatch/cli/pcmd_warp.h                    |    0
 src/plastimatch/cli/pcmd_warp_pointset.cxx         |    0
 src/plastimatch/cli/pcmd_xf_convert.cxx            |    0
 src/plastimatch/cli/pcmd_xf_convert.h              |    0
 src/plastimatch/cli/pcmd_xio_dvh.cxx               |    0
 src/plastimatch/cli/pcmd_xio_dvh.h                 |    0
 src/plastimatch/cli/plastimatch_main.cxx           |   30 +-
 src/plastimatch/clp/CMakeLists.txt                 |    0
 src/plastimatch/clp/plm_clp.cxx                    |    0
 src/plastimatch/clp/plm_clp.h                      |    0
 src/plastimatch/cuda/cuda_probe.h                  |    0
 src/plastimatch/dose/CMakeLists.txt                |   27 +-
 src/plastimatch/dose/dose_volume_functions.cxx     |  115 ++-
 src/plastimatch/dose/dose_volume_functions.h       |    4 +-
 src/plastimatch/dose/rt_beam.cxx                   | 1006 +++++++++++++++----
 src/plastimatch/dose/rt_beam.h                     |  114 ++-
 .../{util/gabor.h => dose/rt_beam_model.cxx}       |   29 +-
 src/plastimatch/dose/rt_beam_model.h               |   21 +
 src/plastimatch/dose/rt_depth_dose.cxx             |  180 ++--
 src/plastimatch/dose/rt_depth_dose.h               |   24 +-
 src/plastimatch/dose/rt_dij.cxx                    |   57 ++
 src/plastimatch/dose/rt_dij.h                      |   48 +
 src/plastimatch/dose/rt_dose.cxx                   | 1033 ++++++++-----------
 src/plastimatch/dose/rt_dose.h                     |   28 +-
 src/plastimatch/dose/rt_dose_timing.h              |   39 +
 src/plastimatch/dose/rt_lut.cxx                    |   36 +-
 src/plastimatch/dose/rt_mebs.cxx                   |  308 +++---
 src/plastimatch/dose/rt_mebs.h                     |   49 +-
 src/plastimatch/dose/rt_parms.cxx                  |   80 +-
 src/plastimatch/dose/rt_parms.h                    |    3 +
 src/plastimatch/dose/rt_plan.cxx                   |  848 ++++++----------
 src/plastimatch/dose/rt_plan.h                     |   24 +-
 src/plastimatch/dose/rt_sigma.cxx                  |  264 ++---
 src/plastimatch/dose/rt_sigma.h                    |   12 +-
 src/plastimatch/dose/rt_spot_map.cxx               |   55 +
 src/plastimatch/dose/rt_spot_map.h                 |   43 +
 src/plastimatch/dose/wed_parms.h                   |    7 +-
 src/plastimatch/opencl/CMakeLists.txt              |    0
 src/plastimatch/opencl/autotune_opencl.cxx         |    0
 src/plastimatch/opencl/autotune_opencl.h           |    0
 src/plastimatch/reconstruct/drr.cxx                |    7 +-
 src/plastimatch/reconstruct/drr_opencl.cxx         |    5 -
 src/plastimatch/reconstruct/fdk.cxx                |    2 +-
 src/plastimatch/register/CMakeLists.txt            |   76 +-
 src/plastimatch/register/bspline.cxx               |  149 +--
 src/plastimatch/register/bspline.h                 |    3 +-
 src/plastimatch/register/bspline_gm.h              |    0
 src/plastimatch/register/bspline_gm.txx            |    6 +-
 src/plastimatch/register/bspline_loop.txx          |   34 +-
 src/plastimatch/register/bspline_mi.cxx            |  365 ++-----
 src/plastimatch/register/bspline_mi.h              |    0
 src/plastimatch/register/bspline_mi.txx            |   16 +-
 src/plastimatch/register/bspline_mi_hist.h         |   77 --
 src/plastimatch/register/bspline_mse.cxx           |   55 +-
 src/plastimatch/register/bspline_mse.h             |    0
 src/plastimatch/register/bspline_mse.txx           |   13 +-
 src/plastimatch/register/bspline_optimize.cxx      |   84 +-
 src/plastimatch/register/bspline_optimize.h        |   10 +-
 .../register/bspline_optimize_lbfgsb.cxx           |   14 +-
 .../register/bspline_optimize_liblbfgs.cxx         |    2 +-
 .../register/bspline_optimize_nlopt.cxx            |    2 +-
 .../register/bspline_optimize_steepest.cxx         |   47 +-
 src/plastimatch/register/bspline_parms.cxx         |   18 +-
 src/plastimatch/register/bspline_parms.h           |   58 +-
 src/plastimatch/register/bspline_regularize.cxx    |    2 -
 src/plastimatch/register/bspline_regularize.h      |    2 -
 src/plastimatch/register/bspline_score.cxx         |   43 +-
 src/plastimatch/register/bspline_score.h           |   40 +-
 src/plastimatch/register/bspline_stage.cxx         |  277 +++---
 src/plastimatch/register/bspline_stage.h           |    2 -
 src/plastimatch/register/bspline_state.cxx         |  218 ++--
 src/plastimatch/register/bspline_state.h           |   35 +-
 src/plastimatch/register/cuda/CMakeLists.txt       |    3 -
 src/plastimatch/register/cuda/bspline_cuda.cu      |   19 +-
 src/plastimatch/register/cuda/bspline_cuda.cxx     |   60 +-
 src/plastimatch/register/cuda/bspline_cuda.h       |   10 +-
 src/plastimatch/register/gpuit_demons.cxx          |    6 +-
 .../register/{bspline_gm.h => groupwise_parms.cxx} |   13 +-
 .../register/{bspline_gm.h => groupwise_parms.h}   |   12 +-
 src/plastimatch/register/histogram.cxx             |   33 +
 src/plastimatch/register/histogram.h               |   38 +
 src/plastimatch/register/itk_align_center.cxx      |   23 +-
 src/plastimatch/register/itk_demons.cxx            |   81 +-
 src/plastimatch/register/itk_registration.cxx      |   71 +-
 .../register/itk_registration_observer.cxx         |   25 +-
 .../{bspline_mi_hist.cxx => joint_histogram.cxx}   |  260 ++++-
 src/plastimatch/register/joint_histogram.h         |   50 +
 src/plastimatch/register/landmark_warp.cxx         |    2 +-
 src/plastimatch/register/metric_parms.cxx          |   54 +
 src/plastimatch/register/metric_parms.h            |   28 +
 .../{translation_mse.h => metric_state.cxx}        |   36 +-
 src/plastimatch/register/metric_state.h            |   39 +
 src/plastimatch/register/process_parms.cxx         |   12 +-
 src/plastimatch/register/rbf_gauss.cxx             |   19 +-
 src/plastimatch/register/registration.cxx          |   65 +-
 src/plastimatch/register/registration.h            |    4 +-
 src/plastimatch/register/registration_data.cxx     |  282 +++++-
 src/plastimatch/register/registration_data.h       |   55 +-
 .../register/registration_metric_type.h            |   18 -
 src/plastimatch/register/registration_parms.cxx    |  230 +----
 src/plastimatch/register/registration_parms.h      |   16 +-
 src/plastimatch/register/registration_resample.cxx |    0
 src/plastimatch/register/registration_resample.h   |    0
 .../register/registration_similarity_data.h        |   24 +
 src/plastimatch/register/registration_util.cxx     |   44 +
 ...registration_resample.h => registration_util.h} |   17 +-
 src/plastimatch/register/shared_parms.cxx          |   17 +
 src/plastimatch/register/shared_parms.h            |    8 +-
 ..._metric_type.cxx => similarity_metric_type.cxx} |   18 +-
 src/plastimatch/register/similarity_metric_type.h  |   19 +
 src/plastimatch/register/stage_parms.cxx           |    4 -
 src/plastimatch/register/stage_parms.h             |    9 +-
 .../register/translation_grid_search.cxx           |  180 ++--
 src/plastimatch/register/translation_mi.cxx        |   21 +-
 src/plastimatch/register/translation_mi.h          |    3 +-
 src/plastimatch/register/translation_mse.cxx       |    8 +-
 src/plastimatch/register/translation_mse.h         |    3 +-
 src/plastimatch/segment/autolabel_parms.cxx        |    4 +-
 src/plastimatch/segment/autolabel_parms.h          |    1 +
 src/plastimatch/segment/mabs.cxx                   |   12 +-
 src/plastimatch/segment/mabs.h                     |    0
 src/plastimatch/segment/mabs_atlas_selection.cxx   |    4 +-
 src/plastimatch/segment/mabs_parms.cxx             |    2 +
 src/plastimatch/segment/mabs_stats.cxx             |    0
 src/plastimatch/segment/mabs_stats.h               |    0
 src/plastimatch/standalone/CMakeLists.txt          |    6 -
 src/plastimatch/standalone/YKThreadRegi.cpp        |    4 -
 src/plastimatch/standalone/bspline_main.cxx        |   49 +-
 src/plastimatch/standalone/bspline_opts.cxx        |    5 +-
 src/plastimatch/standalone/bspline_opts.h          |    3 +
 src/plastimatch/standalone/check_grad.cxx          |   37 +-
 src/plastimatch/standalone/dlib_train.cxx          |    0
 src/plastimatch/standalone/drr_main.cxx            |    6 +-
 src/plastimatch/standalone/gamma_gui.cpp           |  317 ++++++
 src/plastimatch/standalone/gamma_gui.h             |    3 +
 src/plastimatch/standalone/gamma_gui.ui            |   23 +
 src/plastimatch/standalone/hnd_to_pfm.cxx          |    0
 src/plastimatch/standalone/opencl_probe.cxx        |    0
 src/plastimatch/standalone/opencl_probe.h          |    0
 src/plastimatch/standalone/qt_util.cxx             |    2 +-
 src/plastimatch/standalone/qt_util.h               |    2 +-
 src/plastimatch/standalone/shuffle_mha_main.cxx    |    0
 src/plastimatch/standalone/sobp_main.cxx           |   18 +-
 src/plastimatch/standalone/vf_invert_main.cxx      |    0
 src/plastimatch/sys/CMakeLists.txt                 |    5 +-
 src/plastimatch/sys/compiler_warnings.h            |    0
 src/plastimatch/sys/dlib_threads.cxx               |    0
 src/plastimatch/sys/dlib_threads.h                 |    0
 src/plastimatch/sys/logfile.cxx                    |    0
 src/plastimatch/sys/plm_endian.cxx                 |    0
 src/plastimatch/sys/plm_macros.h                   |    0
 src/plastimatch/sys/plm_math.h                     |   29 +-
 src/plastimatch/sys/plm_return_code.h              |    0
 src/plastimatch/sys/plm_sleep.cxx                  |    0
 src/plastimatch/sys/plm_sleep.h                    |    0
 src/plastimatch/sys/plm_timer.cxx                  |    7 +
 src/plastimatch/sys/plm_timer.h                    |    1 +
 src/plastimatch/sys/smart_pointer.h                |    0
 src/plastimatch/sys/string_util.cxx                |   37 +-
 src/plastimatch/sys/string_util.h                  |    6 +-
 src/plastimatch/test/api_test.cxx                  |    0
 src/plastimatch/test/cpp_eps_test.cxx              |    0
 src/plastimatch/test/cpp_limits_test.cxx           |    0
 src/plastimatch/test/cpp_overflow_test.cxx         |    0
 src/plastimatch/test/cpp_sizeof_test.cxx           |    0
 src/plastimatch/test/cpp_template_test.cxx         |   17 +-
 src/plastimatch/test/cuda/cuda_test.cu             |   19 +-
 src/plastimatch/test/dcmtk_test.cxx                |    0
 src/plastimatch/test/dlib_test.cxx                 |    0
 src/plastimatch/test/dlib_thread_test.cxx          |    0
 src/plastimatch/test/gabor_test.cxx                |    0
 src/plastimatch/test/itk_test.cxx                  |    0
 src/plastimatch/test/itk_test_directions.cxx       |    0
 src/plastimatch/test/itk_thread_test.cxx           |    0
 src/plastimatch/test/libyaml_test.cxx              |    0
 src/plastimatch/test/plm_restart_test.cxx          |    0
 src/plastimatch/test/rapidjson_test.cxx            |    0
 src/plastimatch/test/rtplan_test.cxx               |    0
 src/plastimatch/test/smartp_test_i.cxx             |    0
 src/plastimatch/test/smartp_test_ii.cxx            |    0
 src/plastimatch/test/yamlcpp_test.cxx              |    0
 src/plastimatch/util/CMakeLists.txt                |    5 +-
 src/plastimatch/util/dicom_sro_save.cxx            |    0
 src/plastimatch/util/dicom_sro_save.h              |    0
 src/plastimatch/util/distance_map.cxx              |   26 +-
 src/plastimatch/util/distance_map.h                |    7 +
 src/plastimatch/util/gabor.cxx                     |    0
 src/plastimatch/util/gabor.h                       |    0
 src/plastimatch/util/hausdorff_distance.cxx        |   13 +-
 src/plastimatch/util/hausdorff_distance.h          |    4 +
 src/plastimatch/util/image_boundary.cxx            |   45 +-
 src/plastimatch/util/image_boundary.h              |   15 +-
 src/plastimatch/util/image_center.cxx              |    0
 src/plastimatch/util/image_center.h                |    0
 src/plastimatch/util/itk_adjust.cxx                |   73 --
 src/plastimatch/util/itk_distance_map.cxx          |    0
 src/plastimatch/util/itk_threshold.cxx             |    0
 src/plastimatch/util/itk_threshold.h               |    0
 src/plastimatch/util/vf_invert.cxx                 |    0
 src/plastimatch/util/vf_invert.h                   |    0
 src/plastimatch/util/volume_adjust.cxx             |   40 +
 src/plastimatch/util/volume_adjust.h               |   15 +
 430 files changed, 7503 insertions(+), 4957 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a51daaa..d52f0a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ project (plastimatch)
 ## The version here should be equal to the "next release"
 set (PLM_VERSION_MAJOR "1")
 set (PLM_VERSION_MINOR "6")
-set (PLM_VERSION_PATCH "5")
+set (PLM_VERSION_PATCH "6")
 #set (PLM_RELEASE_VERSION FALSE)
 set (PLM_RELEASE_VERSION TRUE)
 
@@ -307,6 +307,7 @@ find_package (Etags)
 #find_package (Fann)
 find_package (FFTW)
 find_package (Git)
+find_package (Kaze)
 find_package (Liblbfgs)
 find_package (NLopt)
 if (PLM_CONFIG_ENABLE_MATLAB)
@@ -365,10 +366,17 @@ add_subdirectory (libs/devillard)
 ##-----------------------------------------------------------------------------
 ##  If using local dlib
 ##-----------------------------------------------------------------------------
-if (NOT DLIB_FOUND)
-    set (DLIB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/dlib-19.1")
-    set (DLIB_LIBRARIES "")
-    set (DLIB_HAVE_LIBRARY FALSE)
+if (dlib_FOUND)
+  set (DLIB_INCLUDE_DIR ${dlib_INCLUDE_DIR})
+  set (DLIB_LIBRARIES ${dlib_LIBRARIES})
+  set (DLIB_FOUND TRUE)
+endif ()
+if (DLIB_FOUND)
+  set (DLIB_HAVE_LIBRARY TRUE)
+else ()
+  set (DLIB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/dlib-19.1")
+  set (DLIB_LIBRARIES "")
+  set (DLIB_HAVE_LIBRARY FALSE)
 endif ()
 
 ##-----------------------------------------------------------------------------
@@ -987,7 +995,7 @@ if (PLM_BUILD_TESTING)
 
   # Copy the lconv script
   configure_file (
-    "${CMAKE_SOURCE_DIR}/run_lcov.sh" 
+    "${CMAKE_SOURCE_DIR}/extra/devtools/run_lcov.sh" 
     "${CMAKE_BINARY_DIR}/run_lcov.sh"
     COPYONLY)
 endif ()
diff --git a/INSTALL.TXT b/INSTALL.TXT
old mode 100755
new mode 100644
diff --git a/LICENSE.TXT b/LICENSE.TXT
old mode 100755
new mode 100644
diff --git a/README.TXT b/README.TXT
old mode 100755
new mode 100644
index 5afbf4f..8c25387
--- a/README.TXT
+++ b/README.TXT
@@ -1,33 +1,30 @@
                         *** Welcome to Plastimatch ***
 
-Plastimatch is a collection of command-line deformable registration 
-software programs, which can be used for anatomic matching of 3D data sets.  
-The main features include:
+Plastimatch is a computer software application which has been designed 
+for volumetric (usually medical) image processing and
+radiation therapy therapy applications.  It can be used 
+for the following purposes:
 
-  1) Image conversion routines
-  2) Patient masking
-  3) B-Spline registration
-  4) Demons registration
-  5) Image warping
+  1) Deformable registration
+  2) Atlas-based segmentation
+  3) Image conversion and manipulation
+  4) Vector field conversion and manipulation
+  5) Gamma analysis
+  6) Dose calculation
+  7) Registration analysis (Jacobian)
+  8) Segmentation analysis (Dice, Hausdorff)
+  9) Many other things
 
-In addition, plastimatch includes routines for:
+For online documentation, please visit:
 
-  1) FDK cone-beam 
-  2) DRR generation
+http://plastimatch.org
 
+Questions, comments, bug reports?  Please post:
 
-For help on installing plastimatch, please read INSTALL.TXT.
-
-For help on using plastimatch, please read PLASTIMATCH.ODT.
-
-An example parameter file is included as REGISTRATION.TXT.
+https://groups.google.com/d/forum/plastimatch
 
 Plastimatch is open source software, and can be used, modified, and 
 distributed, without cost, under a BSD-style license.  This software is 
 intended for research use only, and is not approved by the Food and
 Drug Administration (FDA) for clinical use.  Please see LICENSE.TXT 
 for details.
-
-Questions, comments, bug reports?  Please send to:
-  Greg Sharp, MGH Radiation Oncology
-  <gcsharp A at T partners dot org>
diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt
index 235fcf6..13a9e60 100755
--- a/Testing/CMakeLists.txt
+++ b/Testing/CMakeLists.txt
@@ -31,6 +31,7 @@ set (CONFIG_FILE_LIST
   "plm-bsp-mi-c.txt"
   "plm-bsp-mi-k.txt"
   "plm-bsp-gm-k.txt"
+  "plm-bsp-dmap-k.txt"
   "plm-bsp-sm-multi-a.txt"
   "plm-bsp-cuda.txt"
   "plm-bsp-rect.txt"
@@ -49,6 +50,7 @@ set (CONFIG_FILE_LIST
   "plm-bsp-landmark-e.txt"
   "plm-bsp-double.txt"
   "plm-bsp-regularize-numeric.txt"
+  "plm-reg-align-center.txt"
   "plm-reg-itk-translation.txt"
   "plm-reg-roi-a.txt"
   "plm-reg-roi-b.txt"
@@ -69,12 +71,12 @@ set (CONFIG_FILE_LIST
   "plm-reg-trans-mi-a.txt"
   "plm-reg-autores-a.txt"
   "plm-reg-autores-b.txt"
+  "plm-reg-gw-a.txt"
   "proton-dose-1.txt"
   "proton-dose-2.txt"
-  "proton-dose-3.txt"
   "proton-dose-4.txt"
   "proton-dose-5a.txt"
-  "proton-dose-5g.txt"
+  "proton-dose-5d.txt"
   "proton-dose-6a.txt"
   "speedtest-a.txt"
   "wed-a.txt"
@@ -243,6 +245,9 @@ add_custom_target (speedtest
 ##   gauss-ushort-2    Off-center gauss, ushort
 ##   lung-1            Synthetic lung, tumor position 0
 ##   lung-2            Synthetic lung, tumor position -5
+##   gw-lung-a         Synthetic lung, tumor position -5, in gw dir
+##   gw-lung-b         Synthetic lung, tumor position 0, in gw dir
+##   gw-lung-c         Synthetic lung, tumor position +5, in gw dir
 ##   ptv-1             rect PTV target for dose calculation
 ##   ptv-2             rect PTV target for dose calculation, smaller geometry
 ##   rect-1            Inverted rect, centered
@@ -254,6 +259,11 @@ add_custom_target (speedtest
 ##   rect-7            Standard rect, centered, direction cosines alt-3
 ##   rect-8            Uchar rect, off-center
 ##   rect-9            Uchar rect, centered, higher resolution
+##   rect-10-roi-1
+##   rect-10-roi-2
+##   rect-10
+##   rect-11
+##   rect-11-roi
 ##   rect-12           Small rect, bg=0, fg=10
 ##   rect-13           Small rect, bg=0, fg=11
 ##   rect-14           Small, off-center rect, bg=0, fg=10
@@ -285,7 +295,7 @@ plm_add_test (
 plm_add_test (
   "donut-1"
   ${PLM_PLASTIMATCH_PATH}/plastimatch
-  "synth;--output;${PLM_BUILD_TESTING_DIR}/donut-1.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/donut-1-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/donut-1-ss-list.txt;--output-type;float;--pattern;donut;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--donut-radius;10 10 10;--background;-1000;--foreground;0;--output-dicom;${PLM_BUILD_TESTING_DIR}/donut-1-dicom;--output-prefix;${PLM_BUILD_TESTING_DIR}/donut-1-prefix/"
+  "synth;--output;${PLM_BUILD_TESTING_DIR}/donut-1.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/donut-1-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/donut-1-ss-list.txt;--output-type;float;--pattern;donut;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--donut-radius;10 10 10;--background;-1000;--foreground;0;--dicom-with-uids;false;--output-dicom;${PLM_BUILD_TESTING_DIR}/donut-1-dicom;--output-prefix;${PLM_BUILD_TESTING_DIR}/do [...]
   )
 plm_add_test (
   "gabor-01"
@@ -358,6 +368,21 @@ plm_add_test (
   "synth;--dicom-with-uids;false;--output;${PLM_BUILD_TESTING_DIR}/lung-2.mha;--output-dicom;${PLM_BUILD_TESTING_DIR}/lung-2-dicom;--pattern;lung;--lung-tumor-pos;-5"
   )
 plm_add_test (
+  "gw-lung-a"
+  ${PLM_PLASTIMATCH_PATH}/plastimatch
+  "synth;--output;${PLM_BUILD_TESTING_DIR}/gw/lung-a.mha;--pattern;lung;--lung-tumor-pos;-5"
+  )
+plm_add_test (
+  "gw-lung-b"
+  ${PLM_PLASTIMATCH_PATH}/plastimatch
+  "synth;--output;${PLM_BUILD_TESTING_DIR}/gw/lung-b.mha;--pattern;lung;--lung-tumor-pos;0"
+  )
+plm_add_test (
+  "gw-lung-c"
+  ${PLM_PLASTIMATCH_PATH}/plastimatch
+  "synth;--output;${PLM_BUILD_TESTING_DIR}/gw/lung-c.mha;--pattern;lung;--lung-tumor-pos;5"
+  )
+plm_add_test (
   "ptv-1"
   ${PLM_PLASTIMATCH_PATH}/plastimatch
   "synth;--output;${PLM_BUILD_TESTING_DIR}/ptv-1.mha;--pattern;rect;--dim;60 60 60;--background;0;--foreground;6;--rect-size;20 20 20;--origin;-150 -150 -150;--spacing;5 5 5"
@@ -2301,7 +2326,7 @@ set (PLM_BSPLINE_TEST_UPPER_THRESH "-744.5")
 plm_add_test (
   "plm-reg-align-center"
   ${PLM_PLASTIMATCH_PATH}/plastimatch
-  "${PLM_TESTING_DATA_DIR}/plm-reg-align-center.txt"
+  "${PLM_BUILD_TESTING_DIR}/plm-reg-align-center.txt"
   )
 plm_add_test (
   "plm-reg-align-center-stats"
@@ -2722,6 +2747,29 @@ set_tests_properties (plm-bsp-gm-k-stats PROPERTIES
 set_tests_properties (plm-bsp-gm-k-check PROPERTIES 
   DEPENDS plm-bsp-gm-k-stats)
 
+# plm_add_test (
+#   "plm-bsp-dmap-k" 
+#   ${PLM_PLASTIMATCH_PATH}/plastimatch
+#   "${PLM_BUILD_TESTING_DIR}/plm-bsp-dmap-k.txt"
+#   )
+# plm_add_test (
+#   "plm-bsp-dmap-k-stats"
+#   ${PLM_PLASTIMATCH_PATH}/plastimatch
+#   "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dmap-k-img.mha"
+#   )
+# plmtest_check_interval ("plm-bsp-dmap-k-check"
+#   "${PLM_BUILD_TESTING_DIR}/plm-bsp-dmap-k-stats.stdout.txt"
+#   "AVE *([-0-9.]*)"
+#   "-122.5"
+#   "-121.5"
+#   )
+# set_property (TEST plm-bsp-dmap-k APPEND PROPERTY DEPENDS rect-4)
+# set_property (TEST plm-bsp-dmap-k APPEND PROPERTY DEPENDS rect-8)
+# set_tests_properties (plm-bsp-dmap-k-stats PROPERTIES 
+#   DEPENDS plm-bsp-dmap-k)
+# set_tests_properties (plm-bsp-dmap-k-check PROPERTIES 
+#   DEPENDS plm-bsp-dmap-k-stats)
+
 plm_add_test (
   "plm-bsp-sm-multi-a" 
   ${PLM_PLASTIMATCH_PATH}/plastimatch
@@ -3540,6 +3588,16 @@ set_tests_properties (plm-reg-autores-b-check PROPERTIES
   DEPENDS plm-reg-autores-b-stats)
 
 ## -------------------------------------------------------------------------
+## plastimatch register (group 12)
+##   plm-reg-gw-a         Groupwise registration
+## -------------------------------------------------------------------------
+# plm_add_test (
+#   "plm-reg-gw-a"
+#   ${PLM_PLASTIMATCH_PATH}/plastimatch
+#   "${PLM_BUILD_TESTING_DIR}/plm-reg-gw-a.txt"
+#   )
+
+## -------------------------------------------------------------------------
 ## plastimatch compose
 ##   This test uses registers from gauss-1 to gauss-2 which are done above, 
 ##   and composes with results from an registration from gauss-2 to 
@@ -3640,7 +3698,7 @@ plmtest_check_interval ("plm-compose-c-check"
   "12.6"
   )
 set_tests_properties (plm-compose-c PROPERTIES 
-  DEPENDS "plm-reg-itk-translation;plm-reg-compose")
+  DEPENDS "gauss-5;plm-bsp-mse-h;plm-reg-compose")
 set_tests_properties (plm-compose-c-warp PROPERTIES DEPENDS plm-compose-c)
 set_tests_properties (plm-compose-c-stats PROPERTIES DEPENDS plm-compose-c)
 set_tests_properties (plm-compose-c-check PROPERTIES 
@@ -4248,8 +4306,8 @@ set_tests_properties (plm-xf-convert-f PROPERTIES DEPENDS "rect-2;rect-3")
 ## -------------------------------------------------------------------------
 plm_add_test (
   "vf-invert-zero-1"
-  ${PLM_PLASTIMATCH_PATH}/vf_invert
-  "--input;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--fixed;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--output;${PLM_BUILD_TESTING_DIR}/vf-invert-zero-1.mha"
+  ${PLM_PLASTIMATCH_PATH}/plastimatch
+  "vf-invert;--input;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--fixed;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--output;${PLM_BUILD_TESTING_DIR}/vf-invert-zero-1.mha"
   )
 plm_add_test (
   "vf-invert-zero-1-stats"
@@ -4270,8 +4328,8 @@ set_tests_properties (vf-invert-zero-1-check
 
 plm_add_test (
   "vf-invert-trans-1"
-  ${PLM_PLASTIMATCH_PATH}/vf_invert
-  "--input;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--fixed;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--output;${PLM_BUILD_TESTING_DIR}/vf-invert-trans-1.mha;--iterations;10"
+  ${PLM_PLASTIMATCH_PATH}/plastimatch
+  "vf-invert;--input;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--fixed;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--output;${PLM_BUILD_TESTING_DIR}/vf-invert-trans-1.mha;--iterations;10"
   )
 plm_add_test (
   "vf-invert-trans-1-stats"
@@ -4293,13 +4351,8 @@ set_tests_properties (vf-invert-trans-1-check
 ## -------------------------------------------------------------------------
 ## bragg-curve
 ## proton-dose-1    Flavor a, sobp
-## proton-dose-2    Flavor f, single bragg peak, target, autom. rgcomp
-## proton-dose-3    Flavor g, multiple beam
-## proton-dose-4    Flavor h, load range comp file
 ## proton-dose-5a   Flavor a, sobp target with aperture and rgc
-## proton-dose-5f   Flavor f, sobp target with aperture and rgc
-## proton-dose-5g   Flavor g, sobp target with aperture and rgc
-## proton-dose-5h   Flavor h, sobp target with aperture and rgc
+## proton-dose-5d   Flavor d, sobp target with aperture and rgc
 ## proton-dose-6a   Flavor a, target geometry differs from CT geometry
 ## -------------------------------------------------------------------------
 plm_add_test (
@@ -4314,8 +4367,8 @@ set_tests_properties (bragg-curve-check PROPERTIES DEPENDS bragg-curve)
 
 plm_add_test (
     "proton-dose-1"
-    ${PLM_PLASTIMATCH_PATH}/proton_dose
-    "${PLM_BUILD_TESTING_DIR}/proton-dose-1.txt"
+    ${PLM_PLASTIMATCH_PATH}/plastimatch
+    "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-1.txt"
     )
 plm_add_test (
   "proton-dose-1-stats"
@@ -4335,64 +4388,9 @@ set_tests_properties (proton-dose-1-check
     PROPERTIES DEPENDS proton-dose-1-stats)
 
 plm_add_test (
-    "proton-dose-2"
-    ${PLM_PLASTIMATCH_PATH}/proton_dose
-    "${PLM_BUILD_TESTING_DIR}/proton-dose-2.txt"
-    )
-plm_add_test (
-  "proton-dose-2-stats"
-  ${PLM_PLASTIMATCH_PATH}/plastimatch
-  "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-2.mha"
-  )
-plmtest_check_interval ("proton-dose-2-check"
-  "${PLM_BUILD_TESTING_DIR}/proton-dose-2-stats.stdout.txt"
-  "AVE *([-0-9.]*)"
-  "0.10"
-  "0.12"
-  )
-set_tests_properties (proton-dose-2 PROPERTIES DEPENDS rect-17)
-set_tests_properties (proton-dose-2 PROPERTIES DEPENDS ptv-1)
-set_tests_properties (proton-dose-2-stats
-    PROPERTIES DEPENDS proton-dose-2)
-set_tests_properties (proton-dose-2-check
-    PROPERTIES DEPENDS proton-dose-2-stats)
-
-plm_add_test (
-    "proton-dose-3"
-    ${PLM_PLASTIMATCH_PATH}/proton_dose
-    "${PLM_BUILD_TESTING_DIR}/proton-dose-3.txt"
-    )
-plm_add_test (
-  "proton-dose-3-stats"
-  ${PLM_PLASTIMATCH_PATH}/plastimatch
-  "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-3.mha"
-  )
-plmtest_check_interval ("proton-dose-3-check"
-  "${PLM_BUILD_TESTING_DIR}/proton-dose-3-stats.stdout.txt"
-  "AVE *([-0-9.]*)"
-  "0.21"
-  "0.22"
-  )
-set_tests_properties (proton-dose-3 PROPERTIES DEPENDS rect-17)
-set_tests_properties (proton-dose-3 PROPERTIES DEPENDS ptv-1)
-set_tests_properties (proton-dose-3-stats
-    PROPERTIES DEPENDS proton-dose-3)
-set_tests_properties (proton-dose-3-check
-    PROPERTIES DEPENDS proton-dose-3-stats)
-
-## This seems to not work, gives zero dose.
-#plm_add_test (
-#    "proton-dose-4"
-#    ${PLM_PLASTIMATCH_PATH}/proton_dose
-#    "${PLM_BUILD_TESTING_DIR}/proton-dose-4.txt"
-#    )
-#set_tests_properties (proton-dose-4 PROPERTIES DEPENDS rect-18)
-#set_tests_properties (proton-dose-4 PROPERTIES DEPENDS rgc-1)
-
-plm_add_test (
     "proton-dose-5a"
-    ${PLM_PLASTIMATCH_PATH}/proton_dose
-    "${PLM_BUILD_TESTING_DIR}/proton-dose-5a.txt"
+    ${PLM_PLASTIMATCH_PATH}/plastimatch
+    "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-5a.txt"
     )
 plm_add_test (
   "proton-dose-5a-stats"
@@ -4413,32 +4411,32 @@ set_tests_properties (proton-dose-5a-check
     PROPERTIES DEPENDS proton-dose-5a-stats)
 
 plm_add_test (
-    "proton-dose-5g"
-    ${PLM_PLASTIMATCH_PATH}/proton_dose
-    "${PLM_BUILD_TESTING_DIR}/proton-dose-5g.txt"
+    "proton-dose-5d"
+    ${PLM_PLASTIMATCH_PATH}/plastimatch
+    "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-5d.txt"
     )
 plm_add_test (
-  "proton-dose-5g-stats"
+  "proton-dose-5d-stats"
   ${PLM_PLASTIMATCH_PATH}/plastimatch
-  "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-5g.mha"
+  "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-5d.mha"
   )
-plmtest_check_interval ("proton-dose-5g-check"
-  "${PLM_BUILD_TESTING_DIR}/proton-dose-5g-stats.stdout.txt"
+plmtest_check_interval ("proton-dose-5d-check"
+  "${PLM_BUILD_TESTING_DIR}/proton-dose-5d-stats.stdout.txt"
   "AVE *([-0-9.]*)"
-  "0.365"
-  "0.375"
+  "0.38"
+  "0.39"
   )
-set_tests_properties (proton-dose-5g PROPERTIES DEPENDS rect-17)
-set_tests_properties (proton-dose-5g PROPERTIES DEPENDS ptv-1)
-set_tests_properties (proton-dose-5g-stats
-    PROPERTIES DEPENDS proton-dose-5g)
-set_tests_properties (proton-dose-5g-check
-    PROPERTIES DEPENDS proton-dose-5g-stats)
+set_tests_properties (proton-dose-5d PROPERTIES DEPENDS rect-17)
+set_tests_properties (proton-dose-5d PROPERTIES DEPENDS ptv-1)
+set_tests_properties (proton-dose-5d-stats
+    PROPERTIES DEPENDS proton-dose-5d)
+set_tests_properties (proton-dose-5d-check
+    PROPERTIES DEPENDS proton-dose-5d-stats)
 
 plm_add_test (
     "proton-dose-6a"
-    ${PLM_PLASTIMATCH_PATH}/proton_dose
-    "${PLM_BUILD_TESTING_DIR}/proton-dose-6a.txt"
+    ${PLM_PLASTIMATCH_PATH}/plastimatch
+    "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-6a.txt"
     )
 plm_add_test (
   "proton-dose-6a-stats"
diff --git a/Testing/Data/plm-bsp-dmap-k.txt b/Testing/Data/plm-bsp-dmap-k.txt
new file mode 100644
index 0000000..c69fa19
--- /dev/null
+++ b/Testing/Data/plm-bsp-dmap-k.txt
@@ -0,0 +1,15 @@
+[GLOBAL]
+fixed=@PLM_BUILD_TESTING_DIR@/rect-4.mha
+moving=@PLM_BUILD_TESTING_DIR@/rect-8.mha
+
+vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -vf.mha
+xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -xf.txt
+img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -img.mha
+
+[STAGE]
+xform=bspline
+alg_flavor=k
+metric=dmap
+max_its=20
+grid_spac=10 10 10
+res=2 2 2
diff --git a/Testing/Data/plm-bsp-sm-multi-a.txt b/Testing/Data/plm-bsp-sm-multi-a.txt
index 1290189..3082157 100755
--- a/Testing/Data/plm-bsp-sm-multi-a.txt
+++ b/Testing/Data/plm-bsp-sm-multi-a.txt
@@ -1,6 +1,8 @@
 [GLOBAL]
-fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha
-moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha
+fixed[0]=@PLM_BUILD_TESTING_DIR@/gauss-1.mha
+moving[0]=@PLM_BUILD_TESTING_DIR@/gauss-2.mha
+fixed[1]=@PLM_BUILD_TESTING_DIR@/gauss-1.mha
+moving[1]=@PLM_BUILD_TESTING_DIR@/gauss-2.mha
 
 vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -vf.mha
 xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -xf.txt
@@ -12,8 +14,10 @@ optim=lbfgsb
 impl=plastimatch
 threading=single
 alg_flavor=c
-metric=mi,gm
-metric_lambda=0.1,100
+metric[0]=gm
+metric[1]=mi
+metric_lambda[0]=0.1
+metric_lambda[1]=100
 max_its=5
 convergence_tol=3
 grad_tol=0.1
diff --git a/Testing/Data/plm-reg-align-center.txt b/Testing/Data/plm-reg-align-center.txt
index fb600a4..7933ab7 100755
--- a/Testing/Data/plm-reg-align-center.txt
+++ b/Testing/Data/plm-reg-align-center.txt
@@ -1,8 +1,9 @@
 [GLOBAL]
-fixed=gauss-1.mha
-moving=gauss-6.mha
-xform_out=plm-reg-align-center-xf.txt
-img_out=plm-reg-align-center-img.mha
+fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha
+moving=@PLM_BUILD_TESTING_DIR@/gauss-6.mha
+
+xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -xf.txt
+img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at -img.mha
 
 [STAGE]
 xform=align_center
diff --git a/Testing/Data/plm-reg-gw-a.txt b/Testing/Data/plm-reg-gw-a.txt
new file mode 100755
index 0000000..59c9b55
--- /dev/null
+++ b/Testing/Data/plm-reg-gw-a.txt
@@ -0,0 +1,8 @@
+[GLOBAL]
+group_dir=@PLM_BUILD_TESTING_DIR@/gw
+
+[STAGE]
+xform=translation
+impl=plastimatch
+gridsearch_min_overlap=0.8 0.8 0.8
+res_mm=3 3 3
diff --git a/Testing/Data/plm-reg-multi-a.txt b/Testing/Data/plm-reg-multi-a.txt
index ccb1fa3..5f37349 100755
--- a/Testing/Data/plm-reg-multi-a.txt
+++ b/Testing/Data/plm-reg-multi-a.txt
@@ -3,7 +3,6 @@ fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha
 moving=@PLM_BUILD_TESTING_DIR@/sphere-2.mha
 
 vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-multi-a-vf.nrrd
-xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-multi-a-xf.txt
 img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-multi-a-img.nrrd
 
 [STAGE]
diff --git a/Testing/Data/proton-dose-1.txt b/Testing/Data/proton-dose-1.txt
old mode 100644
new mode 100755
diff --git a/Testing/Data/proton-dose-5g.txt b/Testing/Data/proton-dose-5d.txt
old mode 100644
new mode 100755
similarity index 92%
rename from Testing/Data/proton-dose-5g.txt
rename to Testing/Data/proton-dose-5d.txt
index 4f6c815..9bccb30
--- a/Testing/Data/proton-dose-5g.txt
+++ b/Testing/Data/proton-dose-5d.txt
@@ -1,18 +1,18 @@
-[PLAN]
-patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha
-target = @PLM_BUILD_TESTING_DIR@/ptv-1.mha
-dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at .mha
-
-[BEAM]
-flavor = g
-homo_approx = n
-
-source = 0 -2000 0
-isocenter = 0 0 0
-
-aperture_offset = 1500
-aperture_origin = -75 -75
-aperture_spacing = 3.75 3.75
-aperture_resolution = 41 41
-aperture_smearing = 5
-source_size = 0
+[PLAN]
+patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha
+target = @PLM_BUILD_TESTING_DIR@/ptv-1.mha
+dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at .mha
+
+[BEAM]
+flavor = d
+homo_approx = n
+
+source = 0 -2000 0
+isocenter = 0 0 0
+
+aperture_offset = 1500
+aperture_origin = -75 -75
+aperture_spacing = 3.75 3.75
+aperture_resolution = 41 41
+aperture_smearing = 5
+source_size = 0
diff --git a/Testing/Data/proton-dose-1.txt b/Testing/Data/proton-dose-7a.txt
old mode 100644
new mode 100755
similarity index 66%
copy from Testing/Data/proton-dose-1.txt
copy to Testing/Data/proton-dose-7a.txt
index a9d0d23..d42353f
--- a/Testing/Data/proton-dose-1.txt
+++ b/Testing/Data/proton-dose-7a.txt
@@ -1,24 +1,18 @@
-[PLAN]
-patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha
-dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at .mha
-
-dose_prescription = 70
-
-[BEAM]
-flavor = a
-homo_approx = n
-
-source = 0 -2000 0
-isocenter = 0 0 0
-
-aperture_origin = -10 -10
-aperture_offset = 1500
-aperture_spacing = 1 1
-aperture_resolution = 21 21
-source_size = 0
-prescription_min_max = 70 90
-
-#[PEAK]
-#energy=100.0000
-#spread=1.000000
-#weight=1
+[PLAN]
+patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha
+dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME at .mha
+dose_prescription = 70
+
+[BEAM]
+flavor = a
+homo_approx = n
+source = 0 -2000 0
+isocenter = 0 0 0
+
+aperture_origin = -20 -20
+aperture_offset = 1500
+aperture_spacing = 1 1
+aperture_resolution = 41 41
+source_size = 0
+
+spot = -5,0,120,6.0,1.5
diff --git a/cmake/FindCUDA_wrap.cmake b/cmake/FindCUDA_wrap.cmake
index ee63f8f..0866bd7 100755
--- a/cmake/FindCUDA_wrap.cmake
+++ b/cmake/FindCUDA_wrap.cmake
@@ -23,7 +23,16 @@ else ()
 
   # GCS 2012-05-07: Workaround for poor, troubled FindCUDA
   set (CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE FALSE)
+
   find_package (CUDA QUIET)
+
+  # GCS 2016-12-23: Tell FindCUDA to tell nvcc to use the c++ compiler,
+  # which it doesn't do even if CUDA_HOST_COMPILATION_CPP is true.
+  # This has to be done after calling FindCUDA, because FindCUDA overwrites
+  # the variable.  PS: Merry Christmas!
+  if (NOT MSVC)
+    set (CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}")
+  endif ()
 endif ()
 
 # 14-5-2016 PAOLO: WORKAROUND GCC 6.1 AND CUDA 7.5 INCOMPATIBILITY
diff --git a/cmake/FindKaze.cmake b/cmake/FindKaze.cmake
new file mode 100644
index 0000000..003b4b0
--- /dev/null
+++ b/cmake/FindKaze.cmake
@@ -0,0 +1,35 @@
+# - Find libkaze
+#  KAZE_INCLUDE_DIR - where to find kaze.h, etc.
+#  KAZE_LIBRARIES   - List of libraries when using kaze.
+#  KAZE_FOUND       - True if kaze found.
+
+set (KAZE_DIR "" CACHE PATH "Root of libkaze install tree (optional).")
+
+if (KAZE_INCLUDE_DIR)
+  # Already in cache, be silent
+  set (Kaze_FIND_QUIETLY TRUE)
+endif ()
+
+
+find_path (KAZE_INCLUDE_DIR kimage.h
+  ${KAZE_DIR}/include)
+
+set (KAZE_NAMES kaze)
+find_library (KAZE_LIBRARY NAMES ${KAZE_NAMES}
+  PATHS
+  ${KAZE_DIR}/lib)
+
+# handle the QUIETLY and REQUIRED arguments and set KAZE_FOUND to TRUE if 
+# all listed variables are TRUE
+include (FindPackageHandleStandardArgs)
+find_package_handle_standard_args (Kaze DEFAULT_MSG 
+  KAZE_LIBRARY 
+  KAZE_INCLUDE_DIR)
+
+if (KAZE_FOUND)
+  set (KAZE_LIBRARIES ${KAZE_LIBRARY})
+else ()
+  set (KAZE_LIBRARIES)
+endif ()
+
+mark_as_advanced (KAZE_LIBRARY KAZE_INCLUDE_DIR)
diff --git a/cmake/FindPaxscan.cmake b/cmake/FindPaxscan.cmake
index d5c0b4f..ca07cfc 100755
--- a/cmake/FindPaxscan.cmake
+++ b/cmake/FindPaxscan.cmake
@@ -15,7 +15,7 @@ endif ()
 FIND_PATH (PAXSCAN_INCLUDE_DIR "HcpFuncDefs.h"
   "C:/Program Files/Varian/PaxscanL04/DeveloperFiles/Includes"
   )
-FIND_LIBRARY (PAXSCAN_LIBRARIES VirtCp 
+FIND_LIBRARY (PAXSCAN_LIBRARIES "VirtCp.lib" 
   "C:/Program Files/Varian/PaxscanL04/DeveloperFiles/VirtCpRel")
 
 INCLUDE (FindPackageHandleStandardArgs)
diff --git a/doc/NOTES.TXT b/doc/NOTES.TXT
old mode 100644
new mode 100755
index 394c0d2..f0cfe02
--- a/doc/NOTES.TXT
+++ b/doc/NOTES.TXT
@@ -1,4 +1,371 @@
 ******************************************************************************
+Good ideas
+
+Elastix:
+A good set of random sampling options
+Schedule of grid spacing allows multiple sub-stages
+Parameter file overwrites
+Rigidity penalty
+
+******************************************************************************
+Groupwise registration
+
+Current form:
+fixed=foo.mha
+moving=foo.mha
+
+Future form:
+group=dir/
+
+[GROUP]
+iterations=3
+convergence=XX
+
+(or)
+
+group=dir/
+group_iterations=3
+group_convergence=XX
+
+
+******************************************************************************
+Beam model, spot map
+
+rt_beam_model: TBD.
+
+rt_depth_dose: This contains a single depth-dose curve.  Currently 
+only generated by analytic model.
+
+rt_mebs: This contain a grid of beamlet weights as a function of 
+energy and position.
+
+rt_spot_map: This contains a list of spots, each spot containing 
+spot position, energy, sigma, weight.
+
+rt_dij: This contains a sparse dose grid.  Ideally it should use the 
+same data structure as pcmd_warp_dij.  However, that structure 
+uses ushort.  Need to consider how to mitigate truncation and overflow.
+
+Active scanning:
+
+A beam contains a dij.
+A beam contains a spot map.
+A beam contains a mebs.
+There is a map from mebs to spots.
+
+There is a dij for each meb.
+There is a dij for each spot.
+
+The pre-optimizer calculates dij for each spot.
+For each beamlet:
+  Calculate dij
+  Increment involved spots by dij
+
+An optimizer will take a set of dij, and will create spot weights.
+
+The final calculations sums the weighted dij.
+
+Passive scattering:
+
+A beam contains a mebs.
+The 
+
+
+
+******************************************************************************
+Calc methodology 
+
+1. manual beamlet map
+     compute_beam_data_from_beamlet_map
+       mebs()->clear_depth_dose
+       mebs()->load_beamlet_map
+       update_aperture_and_range_compensator
+         (not implemented)
+2. manual spot map
+3. manual peaks
+     compute_beam_data_from_manual_peaks
+       mebs()->generate_part_num_from_weight
+       compute_beam_modifiers_active_scanning
+       compute_beam_modifiers_passive_scattering
+4. dose prescription
+     mebs()->set_target_depths
+     compute_beam_data_from_prescription
+5. target
+     compute_beam_data_from_target
+       if passive
+         compute_beam_modifiers
+         compute_beam_data_from_prescription
+       if active
+         compute_beam_modifiers_active_scanning
+         compute_particle_number_matrix_from_target_active
+6. 100 MeV sample beam
+     compute_default_beam
+       mebs()->add_peak
+       compute_beam_data_from_manual_peaks
+
+******************************************************************************
+Dose calculation LUTs
+
+rpl_volume.cxx
+--------------
+compute_density_from_HU
+    "From Schneider paper"  (Not clear how.)
+compute_PrSTPR_Schneider_weq_from_HU
+    "From Schneider paper"  (Not clear how.)
+compute_PrSTRP_XiO_MGH_weq_from_HU
+    Not used (?)
+compute_PrWER_from_HU
+    Stopping power / density
+
+rpl_lut.cxx
+-----------
+get_proton_stop
+    energy -> ??
+get_proton_range
+    energy -> ??
+compute_X0_from_HU
+    HU -> radiation length  (Where does this come from?)
+
+
+******************************************************************************
+Global vs stage vs shared
+
+There are only a few small differences.
+
+Review of global options
+
+- No registration is run
+- Allows process stage before first registration stage
+- Global outputs are written after final stage
+-- Written at original resolution, potentially with different options
+- Logfile is global
+-- I suppose you could switch logfile per stage if you wanted
+
+Review of stage options
+
+- Resume stage / finalize stage
+
+******************************************************************************
+Alternate syntax
+
+[METRIC]
+id=0
+metric=mse
+fixed=x1
+moving=y1
+lambda=0.1
+
+[METRIC]
+id=1
+metric=dmap
+fixed=x2
+moving=y2
+lambda=1.0
+histogram_bins=30
+
+[STAGE]
+metric=mse,dmap
+
+Note that this is not more powerful.  Instead we could do this:
+
+fixed[0]=x1
+moving[0]=y1
+metric[0]=mse
+fixed[1]=x2
+moving[1]=y2
+metric[1]=mi
+histogram_bins[1]=30
+
+Also, with the first syntax, you might want some way to specify
+warped images (warped y1 and y2).  
+
+
+******************************************************************************
+Registration similarity parms/data (cont.)
+
+On the use of std::map.
+
+There are three places where it gets used.
+- Shared_parms
+-- Individual maps for filenames fixed, moving, etc
+- Stage_parms
+-- To be added, individual maps for parameters smetric, smetric_lambda
+- Registration_data
+-- Map of Registration_similarity_data's (containing Plm_image's)
+
+After this, the map gets dissolved into a vector of Stage_similarity_data
+
+- Filenames go raw into map for Shared_parms, images get loaded
+  into Registration_data.
+- Smetric gets cooked and split going into vector for Stage_parms.
+- The Registration_similarity_data (and then Stage_similarity_data)
+  seem to need the parameters.
+
+The main question seems to be that parms and images are considered separate.
+What kind of remedies are there for this?
+
+- Keep separate, parallel maps
+-- Registration_similarity_data stays as-is
+-- Individual maps (or Similarity_parms map) remain in Stage_parms
+-- Copy into unified vector of Stage_similarity_data
+- Single unified parameter map, duplicated parms
+-- Upgrade smetric, smetric_lambda to shared parms
+-- Copy parms into unified Registration_similarity_data at same time
+   as image load for each stage
+- Unify Registration_parms and Registration_data
+-- Upgrade smetric, smetric_lambda to shared parms
+-- Create <filename,Plm_image> pairs
+--- Or scoreboard that maps filename -> Plm_image
+-- At filename load, the <filename,Plm_image> pairs are interpreted
+
+The first option seems easiest, and we could eventually upgrade
+to third option later.
+
+The second option is largely similar to the first, and does not appear
+to have significant advantages, with the exception of a unified map.
+
+The third option seems elegant, but may have some fragile points.
+
+- What to do about process section?  Possible solutions:
+-- Update scoreboard entries with process results
+-- Augment scoreboard to include variable
+-- In any case, this is not super-well supported anyway
+- What to do about avoiding repeat loads
+-- Images in scoreboard, filenames get passed to stages
+-- Pointers copied from stage to stage
+
+Similarity_data
+  <fixed_fn,fixed>, <moving_fn,moving>, 
+  smetric, smetric_lambda
+
+Registration_parms
+  list<Stage_parms*>
+
+Stage_parms
+  map<str,Similarity_data>
+
+Final decision: "first option"
+
+******************************************************************************
+Registration similarity parms/data (cont.)
+
+ROIs are different from similarity?  Here are ways they are different.
+
+- Probably ROIs should affect multiple similarity metrics
+- Probably ROIs should affect regularization
+-- This one is not currently implemented
+-- Ideally should be allowed independent of similarity roi
+-- Ideally should be allowed on a per-regularization basis
+
+Current decision.  Make ROI affect multiple similiary metrics.
+
+******************************************************************************
+Registration similarity parms/data (cont.)
+
+Proposed change option 1
+
+Registration_parms
+  list<Stage_parms*>
+  Shared_parms
+    map<str,Similarity_parms>  <- new
+
+Similarity_parms
+  fixed_fn
+  moving_fn
+
+What should happen with un-specified parameters?  Example:
+
+fixed[0] = a.mha
+moving[0] = b.mha
+metric[0] = mi       // A) should this propagate to [1]?
+impl = plastimatch   // B) should this propagate to [1]?
+fixed[1] = c.mha     // C) if moving[1] not specified should anything happen?
+histeq[1] = true     // D) should this propagate to [0]?
+
+Answers:
+
+A)  No.
+B)  No.
+C)  No.
+D)  No.
+
+******************************************************************************
+Registration similarity parms/data (cont.)
+
+Current status 2016-12-28
+
+Registration_parms
+  list<Stage_parms*>
+  Shared_parms
+    map<str,str> fixed_fn, moving_fn, etc
+
+Registration_data
+  map<str,Reg_sim_data>
+  list<str>
+  Stage_parms auto_parms
+
+Bspline_stage
+  Bspline_optimize    <- check_grad, bspline_score only depends on this
+    Bspline_parms
+    Bspline_state     <- needs parms & bxf to initialize
+      Stage_similarity_data  <- newly created bxf depends on master image
+      Bspline_score
+    Bspline_xform     <- might be loaded from disc, might rely on
+    		      	 fixed image size to set # of control points
+
+1a) Load image
+1b) Fixate image
+2a) Load xform
+2b) Fixate xform
+
+N.b. also
+
+  Bspline_options
+    Bspline_parms
+
+
+******************************************************************************
+Registration similarity parms/data
+
+There are three main types of similarity data:
+- parms
+- original images
+- derived images
+
+In 2016-12-22 design (so far), 
+
+- parms
+  -  Read into Stage_parms during parameter file parsing.
+  -  For each stage, copied into Bspline_parms.
+- original images
+  -  Filenames are read into Shared_parms (but update each 
+     stage not implemented) during parameter file parsing.
+  -  Images loaded during load_stage_input(), placed in 
+     Registration_data (Type Similarity_data).
+  -  They are not reloaded each stage because file_names are
+     not copied when new stages are created.
+- derived images
+  -  Images subsampled and grad calculated into Bspline_stage,
+     then copied into Bspline_parms.
+
+Next iteration of design.
+
+- parms
+  -  Read into Stage_parms during parameter file parsing.
+  -  For each stage, copied into Bspline_parms.
+- original images
+  -  Filenames are read into Shared_parms (but update each 
+     stage not implemented) during parameter file parsing.
+  -  Images loaded during load_stage_input(), placed in 
+     Registration_data (type Registration_data::similarity_images).
+  -  They are not reloaded each stage because file_names are
+     not copied when new stages are created.
+- derived images
+  -  Images subsampled and grad calculated into Bspline_stage,
+     then copied into Bspline_parms, type Bspline_data::similarity_images.
+
+
+******************************************************************************
 register_gui
 2016-10-31
 
@@ -1353,35 +1720,6 @@ Or like this:
 
 4) Move source code to src/ subdirectory
 
-***** Consistency of indices *****
-
-By convention:
-
-   k, z = slowest moving index (usually IS)
-   j, y = middle moving index (usually AP)
-   i, x = fastest moving index (usually RL)
-
-Arrays which hold things like the dimensions are indexed as follows:
-
-   dim[0] = dimensions of fastest moving index
-   dim[1] = dimensions of middle moving index
-   dim[2] = dimensions of slowest moving index
-
-Loops should be nested from slowest index to fastest index.  
-Therefore, the correct nesting is:
-
-    for (k = 0; k < fixed->dim[2]; k++) {
-	for (j = 0; j < fixed->dim[1]; j++) {
-	    for (i = 0; i < fixed->dim[0]; i++) { ... } } }
-
-Embedded indices, such as (x,y,z) coordinates of the vector 
-field at a voxel, should be in the order of x, then y, then z.
-
-When you pass indices into a function it should be 
-in order x, then y, then z.  For example:
-
-    int volume_index (int* dims, int i, int j, int k);
-
 ***** How to compile libf2c *****
 
 Edit libf2c/makefile.vc, and change:
diff --git a/doc/STYLE_GUIDE_2.TXT b/doc/STYLE_GUIDE_2.TXT
index ef65db0..11ad334 100644
--- a/doc/STYLE_GUIDE_2.TXT
+++ b/doc/STYLE_GUIDE_2.TXT
@@ -161,6 +161,41 @@ return type:
      object.get_volume_float ();
 
 
+Index convention in images and volumes
+--------------------------------------
+The following convention is used for walking through images
+
+   k, z = slowest moving index (usually IS)
+   j, y = middle moving index (usually AP)
+   i, x = fastest moving index (usually RL)
+
+Arrays which hold things like the dimensions are indexed as follows:
+
+   dim[0] = dimensions of fastest moving index
+   dim[1] = dimensions of middle moving index
+   dim[2] = dimensions of slowest moving index
+
+Loops should be nested from slowest index to fastest index.  
+Therefore, the correct nesting is:
+
+    for (k = 0; k < fixed->dim[2]; k++) {
+	for (j = 0; j < fixed->dim[1]; j++) {
+	    for (i = 0; i < fixed->dim[0]; i++) { ... } } }
+
+Embedded indices, such as (x,y,z) coordinates of the vector 
+field at a voxel, should be in the order of x, then y, then z.
+
+When you pass indices into a function it should be 
+in order x, then y, then z.  For example:
+
+    int volume_index (int* dims, int i, int j, int k);
+
+For 2D images, dim is preferred over ires.  And (j,i) preferred over (r,c).
+But for legacy code, the following should be true:
+
+   r, j, dim[1], ires[1] = slowest moving index (row)
+   c, i, dim[0], ires[0] = fastest moving index (column)
+
 Variable naming for indexing  [Proposed, not implemented]
 ---------------------------------------------------------
 idx	index		one dimensional index
diff --git a/doc/man/drr.1 b/doc/man/drr.1
index 2513da0..c0f44f5 100644
--- a/doc/man/drr.1
+++ b/doc/man/drr.1
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "DRR" "1" "Dec 04, 2016" "Plastimatch 1.6.5" "Plastimatch"
+.TH "DRR" "1" "October 11, 2017" "Plastimatch 1.6.6" "Plastimatch"
 .SH NAME
 drr \- create a digitally reconstructed radiograph
 .
diff --git a/doc/man/fdk.1 b/doc/man/fdk.1
index c51849f..e3c8515 100644
--- a/doc/man/fdk.1
+++ b/doc/man/fdk.1
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "FDK" "1" "Dec 04, 2016" "Plastimatch 1.6.5" "Plastimatch"
+.TH "FDK" "1" "October 11, 2017" "Plastimatch 1.6.6" "Plastimatch"
 .SH NAME
 fdk \- cone-beam reconstruction from projections using the FDK algorithm
 .
@@ -64,7 +64,7 @@ Options:
 .UNINDENT
 .sp
 The usage of the fdk program is best understood by following along
-with the tutorials: fdk_tutorial_i and fdk_tutorial_ii\&.
+with the tutorials: \fIfdk_tutorial_i\fP and \fIfdk_tutorial_ii\fP\&.
 .SH INPUT FILES
 .sp
 Three different formats of input files are supported.  These are:
@@ -87,7 +87,7 @@ with the .txt extension.  For example, if you want to use image_0000.pfm
 in a reconstruction, you should supply another file image_0000.txt
 which contains the geometry.
 A brief description of the geometry file format is given in
-proj_mat_file_format\&.
+\fIproj_mat_file_format\fP\&.
 .sp
 The sequence of files should be stored with the pattern:
 .INDENT 0.0
diff --git a/doc/man/landmark_warp.1 b/doc/man/landmark_warp.1
index c38c56c..2f65948 100644
--- a/doc/man/landmark_warp.1
+++ b/doc/man/landmark_warp.1
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "LANDMARK_WARP" "1" "Dec 04, 2016" "Plastimatch 1.6.5" "Plastimatch"
+.TH "LANDMARK_WARP" "1" "October 11, 2017" "Plastimatch 1.6.6" "Plastimatch"
 .SH NAME
 landmark_warp \- warp an image using point landmarks
 .
diff --git a/doc/man/plastimatch.1 b/doc/man/plastimatch.1
index 24e7197..8aefd7d 100644
--- a/doc/man/plastimatch.1
+++ b/doc/man/plastimatch.1
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "PLASTIMATCH" "1" "Dec 04, 2016" "Plastimatch 1.6.5" "Plastimatch"
+.TH "PLASTIMATCH" "1" "October 11, 2017" "Plastimatch 1.6.6" "Plastimatch"
 .SH NAME
 plastimatch \- register, convert, warp, or manipulate images
 .
@@ -47,16 +47,17 @@ without any additional command line arguments:
 .nf
 .ft C
 $ plastimatch
-plastimatch version 1.6.0\-beta (5023)
+plastimatch version 1.6.6
 Usage: plastimatch command [options]
 Commands:
- add           adjust        average       boundary      crop
- compare       compose       convert       dice          diff
- dmap          dvh           fill          filter        gamma
- header        jacobian      mabs          mask          probe
+ add           adjust        average       bbox          boundary
+ crop          compare       compose       convert       dice
+ diff          dmap          dose          dvh           fill
+ filter        gamma         header        jacobian      mabs
+ mask          maximum       ml\-convert    multiply      probe
  register      resample      scale         segment       stats
  synth         synth\-vf      threshold     thumbnail     union
- warp          xf\-convert
+ vf\-invert     warp          xf\-convert
 
 For detailed usage of a specific command, type:
   plastimatch command
@@ -616,10 +617,11 @@ plastimatch convert \e
 .sp
 In the previous example, the geometry of the output file wasn\(aqt specified.
 When the geometry of a DICOM RT structure set isn\(aqt specified, it is
-assumed to match the geometry of the DICOM CT image associated with the
-contours.  If the associated DICOM CT image is in the same directory as
+assumed to match the geometry of the DICOM (CT, MR, etc)
+image associated with the
+contours.  If the associated DICOM image is in the same directory as
 the structure set file, it will be found automatically.  Otherwise, we
-have to tell plastimatch where it is located with the \-\-dicom\-dir option.
+have to tell plastimatch where it is located with the \-\-referenced\-ct option.
 .INDENT 0.0
 .INDENT 3.5
 .sp
@@ -629,7 +631,7 @@ plastimatch convert \e
   \-\-input structures.dcm \e
   \-\-output\-ss\-img outfile.nrrd \e
   \-\-output\-ss\-list outfile.txt \e
-  \-\-dicom\-dir ../ct\-directory
+  \-\-referenced\-ct ../image\-directory
 .ft P
 .fi
 .UNINDENT
@@ -1132,8 +1134,8 @@ Prior to running the mabs command, you must create a configuration
 file, and you must arrange your training data into the proper
 directory format.
 For a complete description of the command file syntax and
-usage examples, please refer to the mabs_guidebook
-and the segmentation_command_file_reference\&.
+usage examples, please refer to the \fImabs_guidebook\fP
+and the \fIsegmentation_command_file_reference\fP\&.
 .SH PLASTIMATCH MASK
 .sp
 The \fImask\fP command is used to fill an image region with a constant
@@ -1287,7 +1289,7 @@ and each stage begins with a line containing the string "[STAGE]".
 The global section is used to set input files, output files, and
 global parameters, while the each stage section defines a sequential
 stage of processing.  For a complete description of the command file
-syntax, please refer to the registration_command_file_reference\&.
+syntax, please refer to the \fIregistration_command_file_reference\fP\&.
 .SS Examples
 .sp
 If you want to register image_2.mha to match image_1.mha using
@@ -1367,7 +1369,7 @@ res=1 1 1
 .UNINDENT
 .UNINDENT
 .sp
-For more examples, please refer to the image_registration_guidebook\&.
+For more examples, please refer to the \fIimage_registration_guidebook\fP\&.
 .SH PLASTIMATCH RESAMPLE
 .sp
 The \fIresample\fP command can be used to change the geometry of an image.
diff --git a/run_lcov.sh b/run_lcov.sh
deleted file mode 100755
index 10be6e4..0000000
--- a/run_lcov.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#! /bin/sh
-
-lcov --directory . --zerocounters 
-ctest 
-lcov --directory . --capture --output-file app.info 
-genhtml app.info 
-firefox ./index.html
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
old mode 100755
new mode 100644
index 38cf8a2..993e2c8
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -43,6 +43,10 @@ if (FFTW_FOUND)
   set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${FFTW_LIBRARIES})
 endif ()
 
+if (KAZE_FOUND)
+  set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${KAZE_LIBRARIES})
+endif ()
+
 if (LIBDL_FOUND)
   set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} dl)
 endif ()
@@ -93,6 +97,7 @@ endif ()
 
 if (NOT PLM_CONFIG_DISABLE_ISE)
   add_subdirectory (ise)
+  add_subdirectory (fatm)
 endif ()
 
 if (NOT PLM_CONFIG_DISABLE_FATM)
diff --git a/src/plastimatch/CHANGELOG.TXT b/src/plastimatch/CHANGELOG.TXT
index 9ba791e..cd3279f 100644
--- a/src/plastimatch/CHANGELOG.TXT
+++ b/src/plastimatch/CHANGELOG.TXT
@@ -1,3 +1,13 @@
+Version 1.6.6 (tag v1.6.6)
+Wed Oct 11 10:54:34 EDT 2017
+* Support for multi-metric registration
+* Support for multi-planar registration
+* Support image masks in multi-planar registration
+* Support for dmap registration metric type
+* Many dose calculation improvements
+* DICOM RT Ion plan support
+* Many other bug fixes
+
 Version 1.6.5 (tag v1.6.5)
 Sun Dec  4 18:07:24 EST 2016
 * Improved support for DICOM RT ion plan
diff --git a/src/plastimatch/CMakeLists.txt b/src/plastimatch/CMakeLists.txt
old mode 100755
new mode 100644
index df4dc82..4f2a706
--- a/src/plastimatch/CMakeLists.txt
+++ b/src/plastimatch/CMakeLists.txt
@@ -86,7 +86,7 @@ include_directories (AFTER ${MSINTTYPES_INCLUDE_DIR})
 include_directories (AFTER ${RANSAC_INCLUDE_DIRS})
 
 if (${PLM_CONFIG_USE_PATCHED_ITK})
-    include_directories (AFTER ${CMAKE_SOURCE_DIR}/libs/itk-3.20.0)
+  include_directories (AFTER ${CMAKE_SOURCE_DIR}/libs/itk-3.20.0)
 endif ()
 
 if (CUDA_FOUND)
@@ -99,6 +99,9 @@ if (FFTW_FOUND)
   include_directories (BEFORE ${FFTW_INCLUDE_DIR})
   link_directories (${FFTW_DIR})
 endif ()
+if (KAZE_FOUND)
+  include_directories (AFTER ${KAZE_INCLUDE_DIR})
+endif ()
 if (MATLAB_FOUND)
   include_directories (AFTER ${MATLAB_INCLUDE_DIRS})
 endif ()
diff --git a/src/plastimatch/COPYRIGHT.TXT b/src/plastimatch/COPYRIGHT.TXT
old mode 100755
new mode 100644
diff --git a/src/plastimatch/Doxyfile.in b/src/plastimatch/Doxyfile.in
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/CMakeLists.txt b/src/plastimatch/base/CMakeLists.txt
old mode 100644
new mode 100755
index 3bf638d..d5149e8
--- a/src/plastimatch/base/CMakeLists.txt
+++ b/src/plastimatch/base/CMakeLists.txt
@@ -38,6 +38,7 @@ set (PLMBASE_LIBRARY_SRC
   interpolate_macros.h
   itkAndConstantToImageFilter.h
   itkClampCastImageFilter.txx itkClampCastImageFilter.h
+  itk_bbox.cxx itk_bbox.h
   itk_dicom_load.cxx itk_dicom_load.h
   itk_dicom_save.cxx itk_dicom_save.h
   itk_directions.cxx itk_directions.h
@@ -102,6 +103,7 @@ set (PLMBASE_LIBRARY_SRC
   ray_trace_probe.h
   ray_trace_uniform.cxx
   rpl_volume.cxx rpl_volume.h
+  rpl_volume_lut.cxx rpl_volume_lut.h
   rtds_dcmtk.cxx
   rtds_gdcm.cxx
   rt_study.cxx rt_study.h 
@@ -126,6 +128,7 @@ set (PLMBASE_LIBRARY_SRC
   vf_jacobian.cxx vf_jacobian.h
   vf_stats.cxx vf_stats.h
   volume.cxx volume.h
+  volume_boundary_behavior.h
   volume_conv.cxx volume_conv.h
   volume_fill.cxx volume_fill.h
   volume_gaussian.cxx volume_gaussian.h
diff --git a/src/plastimatch/base/aperture.cxx b/src/plastimatch/base/aperture.cxx
old mode 100644
new mode 100755
index 5b08f6e..c2dc6a7
--- a/src/plastimatch/base/aperture.cxx
+++ b/src/plastimatch/base/aperture.cxx
@@ -36,7 +36,7 @@ public:
     Plm_image::Pointer range_compensator_image;
 
     double distance;
-    int dim[2];
+    plm_long dim[2];
     double center[2];
     double spacing[2];
 };
@@ -45,8 +45,8 @@ Aperture::Aperture ()
 {
     this->d_ptr = new Aperture_private;
 
-	/* The aperture and the range compensator are inizialized */
-	this->allocate_aperture_images();
+    /* The aperture and the range compensator are inizialized */
+    this->allocate_aperture_images();
 
     this->vup[0] = 0.0;
     this->vup[1] = 0.0;
@@ -71,8 +71,8 @@ Aperture::Aperture (const Aperture::Pointer& ap)
 {
     this->d_ptr = new Aperture_private (ap->d_ptr);
 
-	/* The aperture and the range compensator are initialized */
-	this->allocate_aperture_images();
+    /* The aperture and the range compensator are initialized */
+    this->allocate_aperture_images();
 
     vec3_copy (this->vup, ap->vup);
     vec3_copy (this->pdn, ap->pdn);
@@ -83,19 +83,19 @@ Aperture::Aperture (const Aperture::Pointer& ap)
     vec3_copy (this->incr_r, ap->incr_r);
     vec3_copy (this->incr_c, ap->incr_c);
 
-	Volume::Pointer ap_tmp = ap->get_aperture_volume();
-	unsigned char* ap_tmp_img = (unsigned char*) ap_tmp->img;
-	Volume::Pointer rc_tmp = ap->get_range_compensator_volume();
-	float* rc_tmp_img = (float*) rc_tmp->img;
+    Volume::Pointer ap_tmp = ap->get_aperture_volume();
+    unsigned char* ap_tmp_img = (unsigned char*) ap_tmp->img;
+    Volume::Pointer rc_tmp = ap->get_range_compensator_volume();
+    float* rc_tmp_img = (float*) rc_tmp->img;
 
-	unsigned char* ap_img = (unsigned char*) this->get_aperture_volume()->img;
-	float* rc_img = (float*) this->get_range_compensator_volume()->img;
+    unsigned char* ap_img = (unsigned char*) this->get_aperture_volume()->img;
+    float* rc_img = (float*) this->get_range_compensator_volume()->img;
 
-	for (int i = 0; i < d_ptr->dim[0] * d_ptr->dim[1]; i++)
-	{
-		ap_img[i] = ap_tmp_img[i];
-		rc_img[i] = rc_tmp_img[i];
-	}
+    for (int i = 0; i < d_ptr->dim[0] * d_ptr->dim[1]; i++)
+    {
+        ap_img[i] = ap_tmp_img[i];
+        rc_img[i] = rc_tmp_img[i];
+    }
 }
 
 Aperture::~Aperture ()
@@ -115,27 +115,27 @@ Aperture::set_distance (double distance)
     d_ptr->distance = distance;
 }
 
-const int*
+const plm_long*
 Aperture::get_dim () const
 {
     return d_ptr->dim;
 }
 
-int
+plm_long
 Aperture::get_dim (int dim) const
 {
     return d_ptr->dim[dim];
 }
 
 void
-Aperture::set_dim (const int* dim)
+Aperture::set_dim (const plm_long* dim)
 {
     d_ptr->dim[0] = dim[0];
     d_ptr->dim[1] = dim[1];
     d_ptr->center[0] = (dim[0]-1) / 2;
     d_ptr->center[1] = (dim[1]-1) / 2;
 
-	this->allocate_aperture_images();
+    this->allocate_aperture_images();
 }
 
 const double*
@@ -239,15 +239,15 @@ Aperture::allocate_aperture_images ()
     Volume *ap_vol = new Volume (dim, origin, spacing, NULL, PT_UCHAR, 1);
     Volume *rc_vol = new Volume (dim, origin, spacing, NULL, PT_FLOAT, 1);
 
-	/* Set the volume to values = 0 for range compensator and 1 for aperture */
-	unsigned char* ap_img = (unsigned char*) ap_vol->img;
-	float* rc_img = (float*) rc_vol->img;
+    /* Set the volume to values = 0 for range compensator and 1 for aperture */
+    unsigned char* ap_img = (unsigned char*) ap_vol->img;
+    float* rc_img = (float*) rc_vol->img;
 
-	for (int i = 0; i < d_ptr->dim[0] * d_ptr->dim[1]; i++)
-	{
-		ap_img[i] = 1;
-		rc_img[i] = 0;
-	}
+    for (int i = 0; i < d_ptr->dim[0] * d_ptr->dim[1]; i++)
+    {
+        ap_img[i] = 1;
+        rc_img[i] = 0;
+    }
 
     d_ptr->aperture_image = Plm_image::New (ap_vol);
     d_ptr->range_compensator_image = Plm_image::New (rc_vol);
@@ -271,6 +271,12 @@ Aperture::get_aperture_volume ()
     return d_ptr->aperture_image->get_volume_uchar ();
 }
 
+Volume*
+Aperture::get_aperture_vol ()
+{
+    return this->get_aperture_volume().get();
+}
+
 void 
 Aperture::set_aperture_image (const char *ap_filename)
 {
@@ -320,8 +326,8 @@ Aperture::apply_smearing_to_aperture (float smearing, float reference_depth)
     int strel_half_size[2];
     int strel_size[2];
 
-	strel_half_size[0] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[0]));
-	strel_half_size[1] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[1]));
+    strel_half_size[0] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[0]));
+    strel_half_size[1] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[1]));
 
     strel_size[0] = 1 + 2 * strel_half_size[0];
     strel_size[1] = 1 + 2 * strel_half_size[1];
@@ -354,9 +360,9 @@ Aperture::apply_smearing_to_aperture (float smearing, float reference_depth)
     Volume::Pointer ap_vol_new = ap_vol->clone ();
     unsigned char* ap_img_new = (unsigned char*) ap_vol_new->img;
 
-    for (int ar = 0; ar < d_ptr->dim[1]; ar++) {
-        for (int ac = 0; ac < d_ptr->dim[0]; ac++) {
-            int aidx = ar * d_ptr->dim[0] + ac;
+    for (plm_long ar = 0; ar < d_ptr->dim[1]; ar++) {
+        for (plm_long ac = 0; ac < d_ptr->dim[0]; ac++) {
+            plm_long aidx = ar * d_ptr->dim[0] + ac;
             unsigned char ap_acc = 0;
             for (int sr = 0; sr < strel_size[1]; sr++) {
                 int pr = ar + sr - strel_half_size[1];
@@ -398,8 +404,8 @@ Aperture::apply_smearing_to_range_compensator (float smearing, float reference_d
     int strel_half_size[2];
     int strel_size[2];
 
-	strel_half_size[0] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[0]));
-	strel_half_size[1] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[1]));
+    strel_half_size[0] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[0]));
+    strel_half_size[1] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[1]));
 
     strel_size[0] = 1 + 2 * strel_half_size[0];
     strel_size[1] = 1 + 2 * strel_half_size[1];
@@ -432,9 +438,9 @@ Aperture::apply_smearing_to_range_compensator (float smearing, float reference_d
     Volume::Pointer rc_vol_new = rc_vol->clone ();
     float* rc_img_new = (float*) rc_vol_new->img;
 
-    for (int ar = 0; ar < d_ptr->dim[1]; ar++) {
-        for (int ac = 0; ac < d_ptr->dim[0]; ac++) {
-            int aidx = ar * d_ptr->dim[0] + ac;
+    for (plm_long ar = 0; ar < d_ptr->dim[1]; ar++) {
+        for (plm_long ac = 0; ac < d_ptr->dim[0]; ac++) {
+            plm_long aidx = ar * d_ptr->dim[0] + ac;
             float rc_acc = FLT_MAX;
             for (int sr = 0; sr < strel_size[1]; sr++) {
                 int pr = ar + sr - strel_half_size[1];
diff --git a/src/plastimatch/base/aperture.h b/src/plastimatch/base/aperture.h
old mode 100644
new mode 100755
index acab887..893d658
--- a/src/plastimatch/base/aperture.h
+++ b/src/plastimatch/base/aperture.h
@@ -24,11 +24,11 @@ public:
     ///@{
 
     /*! \brief Get the aperture dimension, in pixels */
-    const int* get_dim () const;
+    const plm_long* get_dim () const;
     /*! \brief Get the i or j aperture dimension, in pixels */
-    int get_dim (int dim) const;
+    plm_long get_dim (int dim) const;
     /*! \brief Set the aperture dimension, in pixels */
-    void set_dim (const int* dim);
+    void set_dim (const plm_long* dim);
 
     /*! \brief Get the aperture center, in pixels */
     const double* get_center () const;
@@ -74,6 +74,7 @@ public:
     Plm_image::Pointer& get_aperture_image ();
     /*! \brief Get the aperture image as Volume */
     Volume::Pointer& get_aperture_volume ();
+    Volume* get_aperture_vol ();
     /*! \brief Load the aperture image from a file */
     void set_aperture_image (const char *ap_filename);
 
@@ -96,9 +97,9 @@ public:
 
     /*! \brief Expand aperture and smear compensator.  The smearing 
       parameters is defined as mm around the target in the beam eye view frame
-	  at the target minimal depth. */
+      at the target minimal depth. */
     void apply_smearing_to_aperture (float smearing, float target_depth);
-	void apply_smearing_to_range_compensator (float smearing, float target_depth);
+    void apply_smearing_to_range_compensator (float smearing, float target_depth);
     ///@}
 
 public:
diff --git a/src/plastimatch/base/bspline_xform.cxx b/src/plastimatch/base/bspline_xform.cxx
index 68915df..59cbdb4 100644
--- a/src/plastimatch/base/bspline_xform.cxx
+++ b/src/plastimatch/base/bspline_xform.cxx
@@ -201,8 +201,7 @@ bspline_xform_load (const char* filename)
             return 0;
         }
 
-        std::string tag, val;
-        if (!split_tag_val (line, tag, val)) {
+        if (line.find('=') == std::string::npos) {
             /* No "=" found.  Better be the first coefficient. */
             break;
         }
@@ -642,6 +641,22 @@ Bspline_xform::fill_coefficients (float val)
     }
 }
 
+void
+Bspline_xform::jitter_if_zero ()
+{
+    /*   The MI algorithm will get stuck for a set of coefficients all equaling
+     *   zero due to the method we use to compute the cost function gradient.
+     *   However, it is possible we could be inheriting coefficients from a
+     *   prior stage, so we must check for inherited coefficients before
+     *   applying an initial offset to the coefficient array. */
+    for (int i = 0; i < this->num_coeff; i++) {
+        if (this->coeff[i] != 0.0f) {
+            return;
+        }
+    }
+    fill_coefficients (0.01f);
+}
+
 /* Set volume header from B-spline Xform */
 void 
 Bspline_xform::get_volume_header (Volume_header *vh)
@@ -649,3 +664,17 @@ Bspline_xform::get_volume_header (Volume_header *vh)
     vh->set (this->img_dim, this->img_origin, this->img_spacing, 
         this->dc.get_matrix());
 }
+
+void
+Bspline_xform::log_header ()
+{
+    logfile_printf ("BSPLINE XFORM HEADER\n");
+    logfile_printf ("vox_per_rgn = %d %d %d\n", 
+        this->vox_per_rgn[0], this->vox_per_rgn[1], this->vox_per_rgn[2]);
+    logfile_printf ("roi_offset = %d %d %d\n", 
+        this->roi_offset[0], this->roi_offset[1], this->roi_offset[2]);
+    logfile_printf ("roi_dim = %d %d %d\n", 
+        this->roi_dim[0], this->roi_dim[1], this->roi_dim[2]);
+    logfile_printf ("img_dc = %s\n", this->dc.get_string().c_str());
+}
+
diff --git a/src/plastimatch/base/bspline_xform.h b/src/plastimatch/base/bspline_xform.h
index f322560..1d0e8ff 100644
--- a/src/plastimatch/base/bspline_xform.h
+++ b/src/plastimatch/base/bspline_xform.h
@@ -15,6 +15,10 @@
 class Volume;
 class Volume_header;
 
+/*! \brief 
+ * The Bspline_xform class encapsulates the B-spline coefficients 
+ * used by native registration and warping algorithms.
+ */
 class PLMBASE_API Bspline_xform {
 public:
     SMART_POINTER_SUPPORT (Bspline_xform);
@@ -71,7 +75,13 @@ public:
     );
     void save (const char* filename);
     void fill_coefficients (float val);
+    /*! \brief This function jitters the coefficients if they are all zero. 
+     *  It is used to prevent local minima artifact when optimizing an MI cost 
+     *  function for images with the same geometry.
+     */
+    void jitter_if_zero ();
     void get_volume_header (Volume_header *vh);
+    void log_header ();
 };
 
 PLMBASE_C_API Bspline_xform* bspline_xform_load (const char* filename);
diff --git a/src/plastimatch/base/dcmtk_config.h b/src/plastimatch/base/dcmtk_config.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_file.cxx b/src/plastimatch/base/dcmtk_file.cxx
old mode 100755
new mode 100644
index d769363..556b171
--- a/src/plastimatch/base/dcmtk_file.cxx
+++ b/src/plastimatch/base/dcmtk_file.cxx
@@ -246,10 +246,12 @@ Dcmtk_file::load_header (const char *fn) {
     /* PixelSpacing */
     ofrc = dset->findAndGetString (DCM_PixelSpacing, c);
     if (ofrc.good() && c) {
-	float spacing[3];
-	int rc = parse_dicom_float2 (spacing, c);
+	float dcm_spacing[2];
+	int rc = parse_dicom_float2 (dcm_spacing, c);
 	if (!rc) {
-	    spacing[2] = 0.0;
+            float spacing[3] = {
+                dcm_spacing[1], dcm_spacing[0], 0.0
+            };
 	    d_ptr->m_vh.set_spacing (spacing);
 	}
     }
diff --git a/src/plastimatch/base/dcmtk_file.h b/src/plastimatch/base/dcmtk_file.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_image.cxx b/src/plastimatch/base/dcmtk_image.cxx
old mode 100755
new mode 100644
index 1398105..9cc64d9
--- a/src/plastimatch/base/dcmtk_image.cxx
+++ b/src/plastimatch/base/dcmtk_image.cxx
@@ -116,6 +116,8 @@ Dcmtk_rt_study::image_load ()
             df->get_cstr (DCM_StudyDate));
         d_ptr->rt_study_metadata->set_study_time (
             df->get_cstr (DCM_StudyTime));
+        d_ptr->rt_study_metadata->set_study_id (
+            df->get_cstr (DCM_StudyID));
 
         /* Store remaining metadata */
         Metadata::Pointer& study_metadata = d_ptr->rt_study_metadata->get_study_metadata ();
@@ -129,6 +131,7 @@ Dcmtk_rt_study::image_load ()
         dcmtk_copy_into_metadata (image_metadata, df, DCM_Modality);
         dcmtk_copy_into_metadata (image_metadata, df, DCM_InstanceCreationDate);
         dcmtk_copy_into_metadata (image_metadata, df, DCM_InstanceCreationTime);
+        dcmtk_copy_into_metadata (image_metadata, df, DCM_SeriesDescription);
     }
 
     /* Divine image type */
@@ -478,6 +481,8 @@ dcmtk_save_slice (const Rt_study_metadata::Pointer rsm, Dcmtk_slice_data *dsd)
         modality.c_str());
     dataset->putAndInsertString (DCM_SeriesInstanceUID, 
         rsm->get_ct_series_uid());
+    dataset->putAndInsertString (DCM_SeriesDescription, 
+        rsm->get_ct_series_description());
 
     /* Frame of Reference module */
     Dcmtk_module::set_frame_of_reference (dataset, rsm);
@@ -496,7 +501,7 @@ dcmtk_save_slice (const Rt_study_metadata::Pointer rsm, Dcmtk_slice_data *dsd)
     }
 
     /* Image Plane module */
-    tmp = string_format ("%f\\%f", dsd->vol->spacing[0], dsd->vol->spacing[1]);
+    tmp = string_format ("%f\\%f", dsd->vol->spacing[1], dsd->vol->spacing[0]);
     dataset->putAndInsertString (DCM_PixelSpacing, tmp.c_str());
     dataset->putAndInsertString (DCM_ImageOrientationPatient, dsd->iop.c_str());
     dataset->putAndInsertString (DCM_ImagePositionPatient, dsd->ipp.c_str());
@@ -547,6 +552,10 @@ dcmtk_save_slice (const Rt_study_metadata::Pointer rsm, Dcmtk_slice_data *dsd)
         dataset->putAndInsertString (
             DCM_SOPClassUID, UID_NuclearMedicineImageStorage);
     }
+    else if (modality == "US") {
+        dataset->putAndInsertString (
+            DCM_SOPClassUID, UID_UltrasoundImageStorage);
+    }
     else {
         dataset->putAndInsertString (
             DCM_SOPClassUID, UID_CTImageStorage);
diff --git a/src/plastimatch/base/dcmtk_metadata.cxx b/src/plastimatch/base/dcmtk_metadata.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_metadata.h b/src/plastimatch/base/dcmtk_metadata.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_module.cxx b/src/plastimatch/base/dcmtk_module.cxx
index 2887a50..b7bb400 100644
--- a/src/plastimatch/base/dcmtk_module.cxx
+++ b/src/plastimatch/base/dcmtk_module.cxx
@@ -34,12 +34,14 @@ Dcmtk_module::set_general_study (
         rsm->get_study_date());
     dataset->putAndInsertOFStringArray (DCM_StudyTime, 
         rsm->get_study_time());
-    dataset->putAndInsertString (DCM_ReferringPhysicianName, "");
+    dataset->putAndInsertString (DCM_ReferringPhysicianName, 
+        rsm->get_referring_physician_name());
     dcmtk_copy_from_metadata (dataset, rsm->get_study_metadata(), 
         DCM_StudyID, "");
-    dataset->putAndInsertOFStringArray (DCM_AccessionNumber, "");
-    dcmtk_copy_from_metadata (dataset, rsm->get_study_metadata (),
-        DCM_StudyDescription, "");
+    dataset->putAndInsertString (DCM_AccessionNumber,rsm->get_accession_number() );
+    dataset->putAndInsertString (DCM_StudyDescription,rsm->get_study_description() );
+    // dcmtk_copy_from_metadata (dataset, rsm->get_study_metadata (),
+    //     DCM_StudyDescription, "");
     dataset->putAndInsertOFStringArray (DCM_StudyID, 
         rsm->get_study_id());
  }
@@ -75,10 +77,11 @@ Dcmtk_module::set_general_equipment (DcmDataset *dataset,
     const Metadata::Pointer& meta)
 {
     dcmtk_copy_from_metadata (dataset, meta, DCM_Manufacturer, "Plastimatch");
-    dcmtk_copy_from_metadata (dataset, meta, DCM_InstitutionName, "");
+    //dcmtk_copy_from_metadata (dataset, meta, DCM_InstitutionName, "");
     dcmtk_copy_from_metadata (dataset, meta, DCM_StationName, "");
     dcmtk_copy_from_metadata (dataset, meta, DCM_ManufacturerModelName,
         "Plastimatch");
+    dcmtk_copy_from_metadata (dataset, meta, DCM_DeviceSerialNumber, "");
     dcmtk_copy_from_metadata (dataset, meta, DCM_SoftwareVersions,
         PLASTIMATCH_VERSION_STRING);
 }
diff --git a/src/plastimatch/base/dcmtk_rdd.cxx b/src/plastimatch/base/dcmtk_rdd.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_rdd.h b/src/plastimatch/base/dcmtk_rdd.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_rt_study.cxx b/src/plastimatch/base/dcmtk_rt_study.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_rt_study.h b/src/plastimatch/base/dcmtk_rt_study.h
old mode 100755
new mode 100644
index 15461fa..9b14812
--- a/src/plastimatch/base/dcmtk_rt_study.h
+++ b/src/plastimatch/base/dcmtk_rt_study.h
@@ -38,6 +38,7 @@ public:
     const char* get_rtss_series_uid () const;
     const char* get_study_date () const;
     const char* get_study_time () const;
+    const char* get_study_description () const;
     const char* get_study_uid () const;
     std::vector<Dcmtk_slice_data>* get_slice_data();
 
diff --git a/src/plastimatch/base/dcmtk_rtdose.cxx b/src/plastimatch/base/dcmtk_rtdose.cxx
old mode 100755
new mode 100644
index fd4ffba..10b32f1
--- a/src/plastimatch/base/dcmtk_rtdose.cxx
+++ b/src/plastimatch/base/dcmtk_rtdose.cxx
@@ -15,6 +15,7 @@
 #include "dcmtk_rt_study_p.h"
 #include "dcmtk_rtdose.h"
 #include "dcmtk_series.h"
+#include "dcmtk_util.h"
 #include "file_util.h"
 #include "logfile.h"
 #include "plm_image.h"
@@ -330,7 +331,7 @@ Dcmtk_rt_study::save_dose (const char *dicom_dir)
 
     /* SOP common module */
     dataset->putAndInsertString (DCM_SOPClassUID, UID_RTDoseStorage);
-    dataset->putAndInsertString (DCM_SOPInstanceUID, 
+    dcmtk_put (dataset, DCM_SOPInstanceUID, 
         d_ptr->rt_study_metadata->get_dose_instance_uid());
     dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, 
         d_ptr->rt_study_metadata->get_study_date());
@@ -473,7 +474,7 @@ Dcmtk_rt_study::save_dose (const char *dicom_dir)
         DCM_ReferencedStructureSetSequence, dcm_item, -2);
     dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID,
         UID_RTStructureSetStorage);
-    dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID,
+    dcmtk_put (dcm_item, DCM_ReferencedSOPInstanceUID,
         d_ptr->rt_study_metadata->get_rtstruct_instance_uid());
 
     /* Convert image bytes to integer, then add to dataset */
diff --git a/src/plastimatch/base/dcmtk_rtplan.cxx b/src/plastimatch/base/dcmtk_rtplan.cxx
old mode 100755
new mode 100644
index e0dae3b..a2e55dc
--- a/src/plastimatch/base/dcmtk_rtplan.cxx
+++ b/src/plastimatch/base/dcmtk_rtplan.cxx
@@ -190,33 +190,54 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
     /* Frame of reference module */
     dataset->putAndInsertString (DCM_FrameOfReferenceUID, 
         rsm->get_frame_of_reference_uid());
-    dataset->putAndInsertString (DCM_PositionReferenceIndicator, "");
+    dataset->putAndInsertString (DCM_PositionReferenceIndicator, 
+	rsm->get_position_reference_indicator());
 
     /* General equipment module */
     Dcmtk_module::set_general_equipment (dataset,rtplan_metadata);
 
     /* RT general plan module */
-    dataset->putAndInsertString (DCM_RTPlanLabel, "TESTONLY");
-    dataset->putAndInsertString (DCM_RTPlanName, "TESTONLY");
-    dataset->putAndInsertString (DCM_RTPlanDescription, "This is only a test");
-    dataset->putAndInsertString (DCM_RTPlanDate, "");
-    dataset->putAndInsertString (DCM_RTPlanTime, "");
+    dataset->putAndInsertString (DCM_RTPlanLabel,  rtplan->rt_plan_label.c_str());
+    dataset->putAndInsertString (DCM_RTPlanName, rtplan->rt_plan_name.c_str());
+    //dataset->putAndInsertString (DCM_RTPlanDescription, "This is only a test");
+    dataset->putAndInsertString (DCM_RTPlanDate, rtplan->rt_plan_date.c_str());
+    dataset->putAndInsertString (DCM_RTPlanTime, rtplan->rt_plan_time.c_str());
 
-    /* GCS TODO: Add support for PATIENT at some point */
-    // dataset->putAndInsertString (DCM_RTPlanGeometry, "PATIENT");
-    dataset->putAndInsertString (DCM_RTPlanGeometry, "TREATMENT_DEVICE");
+
+    if (rsm->get_rtstruct_instance_uid() == "") {
+        dataset->putAndInsertString (DCM_RTPlanGeometry, "TREATMENT_DEVICE");
+    } else {
+        dataset->putAndInsertString (DCM_RTPlanGeometry, "PATIENT");
+        DcmItem *rsss_item = 0;
+        dataset->findOrCreateSequenceItem (
+            DCM_ReferencedStructureSetSequence, rsss_item, -2);
+        dcmtk_put (rsss_item, DCM_ReferencedSOPClassUID,
+            UID_RTStructureSetStorage);
+        dcmtk_put (rsss_item, DCM_ReferencedSOPInstanceUID,
+            rsm->get_rtstruct_instance_uid());
+    }
+
+    if (rsm->get_dose_instance_uid() != "") {
+        DcmItem *rds_item = 0;
+        dataset->findOrCreateSequenceItem (
+            DCM_ReferencedDoseSequence, rds_item, -2);
+        dcmtk_put (rds_item, DCM_ReferencedSOPClassUID,
+            UID_RTDoseStorage);
+        dcmtk_put (rds_item, DCM_ReferencedSOPInstanceUID,
+            rsm->get_dose_instance_uid());
+    }
 
     /* SOP common module */
     /* GCS TODO: Figure out whether to use Plan or Ion Plan */
     // dataset->putAndInsertString (DCM_SOPClassUID, UID_RTPlanStorage);
     dataset->putAndInsertString (DCM_SOPClassUID, UID_RTIonPlanStorage);
-    dataset->putAndInsertString (DCM_SOPInstanceUID, 
-        d_ptr->rt_study_metadata->get_dose_instance_uid());
-    dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, 
+    dcmtk_put (dataset, DCM_SOPInstanceUID, 
+        d_ptr->rt_study_metadata->get_plan_instance_uid());
+    dataset->putAndInsertString(DCM_InstanceCreationDate, 
         d_ptr->rt_study_metadata->get_study_date());
-    dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, 
+    dataset->putAndInsertString(DCM_InstanceCreationTime, 
         d_ptr->rt_study_metadata->get_study_time());
-
+ 
     /* RT prescription module * GCS TODO */
         
     /* RT tolerance tables */
@@ -237,10 +258,21 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
             rtplan->tolerance_table_top_longitudinal);
         dcmtk_put (iots_item, DCM_TableTopLateralPositionTolerance,
             rtplan->tolerance_table_top_lateral);
+        dcmtk_put (iots_item, DCM_TableTopPitchAngleTolerance,
+            rtplan->tolerance_table_top_pitch);
+        dcmtk_put (iots_item, DCM_TableTopRollAngleTolerance,
+            rtplan->tolerance_table_top_roll);
         dcmtk_put (iots_item, DCM_SnoutPositionTolerance,
             rtplan->tolerance_snout_position);
     }
-        
+
+    /* RT patient setup module */
+    DcmItem *ps_item = 0;
+    dataset->findOrCreateSequenceItem (
+        DCM_PatientSetupSequence, ps_item, -2);
+    dcmtk_put (ps_item, DCM_PatientSetupNumber, 1);
+    dcmtk_put (ps_item, DCM_PatientPosition, rtplan->patient_position);
+    
     /* RT fraction scheme module */
     DcmItem *fgs_item = 0;
     dataset->findOrCreateSequenceItem (
@@ -249,11 +281,16 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
     dcmtk_put (fgs_item, DCM_NumberOfFractionsPlanned,
         rtplan->number_of_fractions_planned);
     dcmtk_put (fgs_item, DCM_NumberOfBeams, rtplan->beamlist.size());
+    dcmtk_put (fgs_item, DCM_FractionGroupDescription, rtplan->fraction_group_description.c_str());
+    dcmtk_put (fgs_item, DCM_NumberOfFractionPatternDigitsPerDay, 
+	       rtplan->number_of_fraction_pattern_digits_per_day.c_str());
+    dcmtk_put (fgs_item, DCM_RepeatFractionCycleLength, rtplan->repeat_fraction_cycle_length.c_str());
+    dcmtk_put (fgs_item, DCM_FractionPattern, rtplan->fraction_pattern.c_str());
     for (size_t b = 0; b < rtplan->beamlist.size(); b++) {
         DcmItem *rbs_item = 0;
         fgs_item->findOrCreateSequenceItem (
             DCM_ReferencedBeamSequence, rbs_item, -2);
-        dcmtk_put (rbs_item, DCM_ReferencedBeamNumber, b);
+        dcmtk_put (rbs_item, DCM_ReferencedBeamNumber, b+1);
         Rtplan_beam *beam = rtplan->beamlist[b];
         dcmtk_put (rbs_item, DCM_BeamMeterset, 
             beam->final_cumulative_meterset_weight);
@@ -269,7 +306,7 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
         DcmItem *ib_item = 0;
         dataset->findOrCreateSequenceItem (
             DCM_IonBeamSequence, ib_item, -2);
-        s = PLM_to_string (b);
+        s = PLM_to_string (b+1);
         ib_item->putAndInsertString (DCM_BeamNumber, s.c_str());
 
         Rtplan_beam *beam = rtplan->beamlist[b];
@@ -285,14 +322,28 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
             "STATIONARY");
 #endif
         ib_item->putAndInsertString (DCM_TreatmentMachineName,
-            "Reference machine");
+	    beam->treatment_machine_name.c_str());
+        ib_item->putAndInsertString (DCM_Manufacturer,
+	    beam->manufacturer.c_str());
+        ib_item->putAndInsertString (DCM_InstitutionName,
+	    beam->institution_name.c_str());
+        ib_item->putAndInsertString (DCM_InstitutionAddress,
+	    beam->institution_address.c_str());
+        ib_item->putAndInsertString (DCM_InstitutionalDepartmentName,
+	    beam->institutional_department_name.c_str());
+        ib_item->putAndInsertString (DCM_ManufacturerModelName,
+	    beam->manufacturer_model_name.c_str());
         ib_item->putAndInsertString (DCM_PrimaryDosimeterUnit, "NP");
         if (rtplan->tolerance_table_label != "") {
             dcmtk_put (ib_item, DCM_ReferencedToleranceTableNumber, 0);
         }
+	if (rtplan->patient_position != "") {
+            dcmtk_put (ib_item, DCM_ReferencedPatientSetupNumber, 1);
+	}
         ib_item->putAndInsertString (DCM_VirtualSourceAxisDistances,
-            "2000\\2000");
-        ib_item->putAndInsertString (DCM_TreatmentDeliveryType, "TREATMENT");
+	    beam->virtual_source_axis_distances.c_str());
+        ib_item->putAndInsertString (DCM_TreatmentDeliveryType,
+	    beam->treatment_delivery_type.c_str());
         ib_item->putAndInsertString (DCM_NumberOfWedges, "0");
         ib_item->putAndInsertString (DCM_NumberOfCompensators, "0");
         ib_item->putAndInsertString (DCM_NumberOfBoli, "0");
@@ -318,11 +369,14 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
             DcmItem *rs_item = 0;
             ib_item->findOrCreateSequenceItem (
                 DCM_RangeShifterSequence, rs_item, -2);
-            rs_item->putAndInsertString (DCM_RangeShifterNumber, "0");
+            rs_item->putAndInsertString (DCM_RangeShifterNumber, 
+                rtplan->range_shifter_number.c_str());
             rs_item->putAndInsertString (DCM_RangeShifterID,
                 rtplan->range_shifter_id.c_str());
             rs_item->putAndInsertString (DCM_AccessoryCode,
                 rtplan->range_shifter_code.c_str());
+            rs_item->putAndInsertString (DCM_RangeShifterType,
+                rtplan->range_shifter_type.c_str());
         }
         if (rtplan->range_modulator_id != "") {
             DcmItem *rm_item = 0;
@@ -334,10 +388,15 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
             rm_item->putAndInsertString (DCM_AccessoryCode,
                 rtplan->range_modulator_code.c_str());
         }
-        ib_item->putAndInsertString (DCM_NumberOfRangeShifters, "0");
-        ib_item->putAndInsertString (DCM_NumberOfLateralSpreadingDevices, "0");
+        ib_item->putAndInsertString (DCM_NumberOfRangeShifters, 
+	    rtplan->number_of_range_shifters.c_str());
+        ib_item->putAndInsertString (DCM_NumberOfLateralSpreadingDevices,"0"); 
         ib_item->putAndInsertString (DCM_NumberOfRangeModulators, "0");
         ib_item->putAndInsertString (DCM_PatientSupportType, "TABLE");
+        ib_item->putAndInsertString (DCM_PatientSupportID, 
+            rtplan->patient_support_id.c_str());
+        ib_item->putAndInsertString (DCM_PatientSupportAccessoryCode, 
+            rtplan->patient_support_accessory_code.c_str());
         dcmtk_put (ib_item, DCM_FinalCumulativeMetersetWeight,
             beam->final_cumulative_meterset_weight);
 
@@ -354,19 +413,52 @@ Dcmtk_rt_study::save_rtplan (const char *dicom_dir)
             cp_item->putAndInsertString (DCM_CumulativeMetersetWeight,
                 s.c_str());
 	    if (c == 0) {
-                dcmtk_put (cp_item, DCM_SnoutPosition, 
-                    beam->snout_position);
+                s = PLM_to_string (beam->snout_position);
+                cp_item->putAndInsertString (DCM_SnoutPosition, s.c_str());
+                s = PLM_to_string (beam->gantry_angle);
+                cp_item->putAndInsertString (DCM_GantryAngle, s.c_str());
+                cp_item->putAndInsertString (DCM_GantryRotationDirection,
+                    beam->gantry_rotation_direction.c_str());
+                s = PLM_to_string (beam->gantry_pitch_angle);
+	        cp_item->putAndInsertString (DCM_GantryPitchAngle, s.c_str());
+	        cp_item->putAndInsertString (DCM_GantryPitchRotationDirection, 
+	            beam-> gantry_pitch_rotation_direction.c_str());		
+                s = PLM_to_string (beam->beam_limiting_device_angle);
+	        cp_item->putAndInsertString (DCM_BeamLimitingDeviceAngle, s.c_str());
+	        cp_item->putAndInsertString (DCM_BeamLimitingDeviceRotationDirection, 
+	            beam-> beam_limiting_device_rotation_direction.c_str());
+                s = PLM_to_string (beam->patient_support_angle);
+	        cp_item->putAndInsertString (DCM_PatientSupportAngle, s.c_str());
+	        cp_item->putAndInsertString (DCM_PatientSupportRotationDirection, 
+	            beam-> patient_support_rotation_direction.c_str());
+                s = PLM_to_string (beam->table_top_vertical_position);
+	        cp_item->putAndInsertString (DCM_TableTopVerticalPosition, s.c_str());
+                s = PLM_to_string (beam->table_top_longitudinal_position);
+	        cp_item->putAndInsertString (DCM_TableTopLongitudinalPosition, s.c_str());
+                s = PLM_to_string (beam->table_top_lateral_position);
+	        cp_item->putAndInsertString (DCM_TableTopLateralPosition, s.c_str());
+                s = PLM_to_string (beam->table_top_pitch_angle);
+	        cp_item->putAndInsertString (DCM_TableTopPitchAngle, s.c_str());
+	        cp_item->putAndInsertString (DCM_TableTopPitchRotationDirection, 
+	            beam-> table_top_pitch_rotation_direction.c_str());
+                s = PLM_to_string (beam->table_top_roll_angle);
+	        cp_item->putAndInsertString (DCM_TableTopRollAngle, s.c_str());
+	        cp_item->putAndInsertString (DCM_TableTopRollRotationDirection, 
+	            beam-> table_top_roll_rotation_direction.c_str());
+		s = string_format ("%f\\%f\\%f", 
+		    beam->isocenter_position[0],
+		    beam->isocenter_position[1],
+		    beam->isocenter_position[2]);
+	        cp_item->putAndInsertString (DCM_IsocenterPosition, s.c_str());		
 	    }
             s = PLM_to_string (cp->nominal_beam_energy);
             cp_item->putAndInsertString (DCM_NominalBeamEnergy, s.c_str());
-            s = PLM_to_string (cp->gantry_angle);
-            cp_item->putAndInsertString (DCM_GantryAngle, s.c_str());
-            cp_item->putAndInsertString (DCM_GantryRotationDirection,
-                cp->gantry_rotation_direction.c_str());
+
             s = PLM_to_string (cp->number_of_paintings);
             cp_item->putAndInsertString (DCM_NumberOfPaintings,
                 s.c_str());
-	    cp_item->putAndInsertString (DCM_ScanSpotTuneID, cp->scan_spot_tune_id.c_str());
+	    cp_item->putAndInsertString (DCM_ScanSpotTuneID, 
+                cp->scan_spot_tune_id.c_str());
             s = string_format ("%f\\%f", cp->scanning_spot_size[0],
                 cp->scanning_spot_size[1]);
             cp_item->putAndInsertString (DCM_ScanningSpotSize,
diff --git a/src/plastimatch/base/dcmtk_rtss.cxx b/src/plastimatch/base/dcmtk_rtss.cxx
old mode 100755
new mode 100644
index 34ec7f1..8886d18
--- a/src/plastimatch/base/dcmtk_rtss.cxx
+++ b/src/plastimatch/base/dcmtk_rtss.cxx
@@ -14,6 +14,7 @@
 #include "dcmtk_rt_study_p.h"
 #include "dcmtk_series.h"
 #include "dcmtk_slice_data.h"
+#include "dcmtk_util.h"
 #include "file_util.h"
 #include "logfile.h"
 #include "metadata.h"
@@ -72,6 +73,10 @@ Dcmtk_rt_study::rtss_load (void)
     }
 
     /* FIX: load metadata such as patient name, etc. */
+    if (d_ptr->rt_study_metadata) {
+        d_ptr->rt_study_metadata->set_rtstruct_instance_uid (
+	    ds_rtss->get_cstr (DCM_SOPInstanceUID));
+    }
 
     /* ReferencedFrameOfReferenceSequence */
     DcmSequenceOfItems *seq = 0;
@@ -269,7 +274,7 @@ Dcmtk_rt_study::save_rtss (const char *dicom_dir)
     dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, 
         PLM_UID_PREFIX);
     dataset->putAndInsertString (DCM_SOPClassUID, UID_RTStructureSetStorage);
-    dataset->putAndInsertString (DCM_SOPInstanceUID, 
+    dcmtk_put (dataset, DCM_SOPInstanceUID, 
         d_ptr->rt_study_metadata->get_rtstruct_instance_uid());
     dataset->putAndInsertOFStringArray (DCM_StudyDate, 
         d_ptr->rt_study_metadata->get_study_date());
diff --git a/src/plastimatch/base/dcmtk_rtss.h b/src/plastimatch/base/dcmtk_rtss.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_series.cxx b/src/plastimatch/base/dcmtk_series.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_series.h b/src/plastimatch/base/dcmtk_series.h
index 17617aa..cd6717b 100755
--- a/src/plastimatch/base/dcmtk_series.h
+++ b/src/plastimatch/base/dcmtk_series.h
@@ -21,7 +21,7 @@ class Plm_image;
 
 typedef std::list<Dcmtk_file::Pointer> Dcmtk_file_list;
 
-class Dcmtk_series 
+class PLMBASE_API Dcmtk_series 
 {
 public:
     Dcmtk_series ();
diff --git a/src/plastimatch/base/dcmtk_slice_data.h b/src/plastimatch/base/dcmtk_slice_data.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_uid.cxx b/src/plastimatch/base/dcmtk_uid.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_uid.h b/src/plastimatch/base/dcmtk_uid.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dcmtk_util.cxx b/src/plastimatch/base/dcmtk_util.cxx
old mode 100755
new mode 100644
index fc747f6..6a9f49b
--- a/src/plastimatch/base/dcmtk_util.cxx
+++ b/src/plastimatch/base/dcmtk_util.cxx
@@ -46,6 +46,12 @@ dcmtk_put (DcmItem* item, const DcmTag &tag, const std::string& s)
     return item->putAndInsertString (tag, s.c_str());
 }
 
+OFCondition
+dcmtk_put (DcmItem* item, const DcmTag &tag, const char* s)
+{
+    return item->putAndInsertString (tag, s);
+}
+
 template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, int);
 template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, size_t);
 template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, float);
diff --git a/src/plastimatch/base/dcmtk_util.h b/src/plastimatch/base/dcmtk_util.h
old mode 100755
new mode 100644
index 048abab..79250fa
--- a/src/plastimatch/base/dcmtk_util.h
+++ b/src/plastimatch/base/dcmtk_util.h
@@ -19,5 +19,7 @@ template<class T> PLMBASE_API OFCondition
 dcmtk_put (DcmItem*, const DcmTag &, T);
 PLMBASE_API OFCondition
 dcmtk_put (DcmItem*, const DcmTag &, const std::string&);
+PLMBASE_API OFCondition
+dcmtk_put (DcmItem*, const DcmTag &, const char*);
 
 #endif
diff --git a/src/plastimatch/base/dicom.dic b/src/plastimatch/base/dicom.dic
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dicom_util.cxx b/src/plastimatch/base/dicom_util.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/dicom_util.h b/src/plastimatch/base/dicom_util.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/direction_cosines.cxx b/src/plastimatch/base/direction_cosines.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/direction_cosines.h b/src/plastimatch/base/direction_cosines.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/direction_matrices.cxx b/src/plastimatch/base/direction_matrices.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/direction_matrices.h b/src/plastimatch/base/direction_matrices.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/float_pair_list.cxx b/src/plastimatch/base/float_pair_list.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/float_pair_list.h b/src/plastimatch/base/float_pair_list.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gaussian.cxx b/src/plastimatch/base/gaussian.cxx
old mode 100755
new mode 100644
index a45982b..4ccebaa
--- a/src/plastimatch/base/gaussian.cxx
+++ b/src/plastimatch/base/gaussian.cxx
@@ -32,7 +32,6 @@ create_ker (float coeff, int half_width)
     for (i = 0; i < width; i++) {
 	ker[i] = ker[i] / sum;
     }
-
     return ker;
 }
 
diff --git a/src/plastimatch/base/gaussian.h b/src/plastimatch/base/gaussian.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_dose.cxx b/src/plastimatch/base/gdcm1_dose.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_dose.h b/src/plastimatch/base/gdcm1_dose.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_file.cxx b/src/plastimatch/base/gdcm1_file.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_file.h b/src/plastimatch/base/gdcm1_file.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_rdd.cxx b/src/plastimatch/base/gdcm1_rdd.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_rdd.h b/src/plastimatch/base/gdcm1_rdd.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_rtss.cxx b/src/plastimatch/base/gdcm1_rtss.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_rtss.h b/src/plastimatch/base/gdcm1_rtss.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_series.cxx b/src/plastimatch/base/gdcm1_series.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_series.h b/src/plastimatch/base/gdcm1_series.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_series_helper_2.cxx b/src/plastimatch/base/gdcm1_series_helper_2.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_series_helper_2.h b/src/plastimatch/base/gdcm1_series_helper_2.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_util.cxx b/src/plastimatch/base/gdcm1_util.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm1_util.h b/src/plastimatch/base/gdcm1_util.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm2_util.cxx b/src/plastimatch/base/gdcm2_util.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/gdcm2_util.h b/src/plastimatch/base/gdcm2_util.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/hnd_io.cxx b/src/plastimatch/base/hnd_io.cxx
old mode 100644
new mode 100755
index 823ba66..3749c56
--- a/src/plastimatch/base/hnd_io.cxx
+++ b/src/plastimatch/base/hnd_io.cxx
@@ -85,7 +85,7 @@ hnd_set_proj_matrix (
     vec3_copy (cam, tgt);
     vec3_sub2 (cam, tmp);
 
-    pmat->set (cam, tgt, vup, sid, pmat->ic, ps, proj->dim);
+    pmat->set (cam, tgt, vup, sid, pmat->ic, ps);
 }
 
 /* -----------------------------------------------------------------------
diff --git a/src/plastimatch/base/interpolate.cxx b/src/plastimatch/base/interpolate.cxx
old mode 100644
new mode 100755
index c355718..39305b7
--- a/src/plastimatch/base/interpolate.cxx
+++ b/src/plastimatch/base/interpolate.cxx
@@ -40,6 +40,50 @@ li_clamp (
     *fa1 = 1.0f - *fa2;
 }
 
+/* Clipping is done by setting fractional values to 0.f */
+static void
+li_noclamp (
+    plm_long* f,   /* Output: x, y, or z coord of "floor" pixel */
+    float* fa1,	   /* Output: Fraction of interpolant for lower index voxel */
+    float* fa2,    /* Output: Fraction of interpolant for upper index voxel */
+    float idx,     /* Input:  (Unrounded) pixel coordinate (in vox) */
+    plm_long dmax  /* Input:  Maximum coordinate in this dimension */
+)
+{
+    *f = FLOOR_PLM_LONG (idx);
+    *fa2 = idx - *f;
+    *fa1 = 1.0f - *fa2;
+    if (*f < 0) {
+        *fa1 = 0.f;
+        if (*f < -1) {
+            *fa2 = 0.f;
+            return;
+        }
+    }
+    if (*f > dmax - 2) {
+        *fa2 = 0.f;
+        if (*f > dmax - 1) {
+            *fa1 = 0.f;
+            return;
+        }
+    }
+}
+
+/* Simple li, with no processing */
+static void
+li (
+    plm_long* f,   /* Output: x, y, or z coord of "floor" pixel */
+    float* fa1,	   /* Output: Fraction of interpolant for lower index voxel */
+    float* fa2,    /* Output: Fraction of interpolant for upper index voxel */
+    float idx,     /* Input:  (Unrounded) pixel coordinate (in vox) */
+    plm_long dmax  /* Input:  Maximum coordinate in this dimension */
+)
+{
+    *f = FLOOR_PLM_LONG (idx);
+    *fa2 = idx - *f;
+    *fa1 = 1.0f - *fa2;
+}
+
 void
 li_clamp_3d (
     const float mijk[3],  /* Input:  Unrounded pixel coordinates in vox */
@@ -47,7 +91,7 @@ li_clamp_3d (
     plm_long mijk_r[3],   /* Ouptut: "round" pixel in moving img in vox*/
     float li_frac_1[3],   /* Output: Fraction for upper index voxel */
     float li_frac_2[3],   /* Output: Fraction for lower index voxel */
-    Volume *moving        /* Input:  Volume (for dims) */
+    const Volume *moving  /* Input:  Volume (for dims) */
 )
 {
     li_clamp (mijk[0], moving->dim[0]-1, &mijk_f[0], 
@@ -58,6 +102,36 @@ li_clamp_3d (
 	&mijk_r[2], &li_frac_1[2], &li_frac_2[2]);
 }
 
+void
+li_noclamp_3d (
+    plm_long ijk_f[3],
+    float li_frac_1[3],
+    float li_frac_2[3],
+    const float ijk[3],
+    const plm_long dim[3]
+)
+{
+    li_noclamp (&ijk_f[0], &li_frac_1[0], &li_frac_2[0], 
+        ijk[0], dim[0]);
+    li_noclamp (&ijk_f[1], &li_frac_1[1], &li_frac_2[1], 
+        ijk[1], dim[1]);
+    li_noclamp (&ijk_f[2], &li_frac_1[2], &li_frac_2[2], 
+        ijk[2], dim[2]);
+}
+
+void
+li_2d (
+    plm_long *ijk_f,
+    float *li_frac_1,
+    float *li_frac_2,
+    const float *ijk,
+    const plm_long *dim
+)
+{
+    li (&ijk_f[0], &li_frac_1[0], &li_frac_2[0], ijk[0], dim[0]);
+    li (&ijk_f[1], &li_frac_1[1], &li_frac_2[1], ijk[1], dim[1]);
+}
+
 float
 li_value (
     float fx1, float fx2,  /* Input:  Fraction of upper, lower x voxel */
diff --git a/src/plastimatch/base/interpolate.h b/src/plastimatch/base/interpolate.h
old mode 100644
new mode 100755
index d6cb63a..85aba70
--- a/src/plastimatch/base/interpolate.h
+++ b/src/plastimatch/base/interpolate.h
@@ -16,14 +16,35 @@ PLMBASE_C_API void li_clamp (
     plm_long* mar, 
     float* fa1, float* fa2
 );
+
 PLMBASE_C_API void li_clamp_3d (
     const float mijk[3],
     plm_long mijk_f[3],
     plm_long mijk_r[3],
     float li_frac_1[3],
     float li_frac_2[3],
-    Volume *moving
+    const Volume *moving
 );
+
+/* Compute only fractional components, do not solve for value.  
+   Clamping is not done; instead, fractions are set to 0.f if xyz 
+   lies outside limits of dim. */
+PLMBASE_C_API void li_noclamp_3d (
+    plm_long ijk_f[3],
+    float li_frac_1[3],
+    float li_frac_2[3],
+    const float ijk[3],
+    const plm_long dim[3]
+);
+
+PLMBASE_C_API void li_2d (
+    plm_long *ijk_f,
+    float *li_frac_1,
+    float *li_frac_2,
+    const float *ijk,
+    const plm_long *dim
+);
+
 PLMBASE_C_API float li_value (
     float fx1, float fx2,
     float fy1, float fy2, 
diff --git a/src/plastimatch/base/itkClampCastImageFilter.h b/src/plastimatch/base/itkClampCastImageFilter.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itkClampCastImageFilter.txx b/src/plastimatch/base/itkClampCastImageFilter.txx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_bbox.cxx b/src/plastimatch/base/itk_bbox.cxx
new file mode 100644
index 0000000..9b89407
--- /dev/null
+++ b/src/plastimatch/base/itk_bbox.cxx
@@ -0,0 +1,50 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmbase_config.h"
+#include <float.h>
+#include "itkContinuousIndex.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+
+#include "itk_bbox.h"
+#include "itk_image.h"
+
+void
+itk_bbox (UCharImageType::Pointer img, float *bbox)
+{
+    for (int d = 0; d < 3; d++)
+    {
+        bbox[2*d+0] =  FLT_MAX;
+        bbox[2*d+1] = -FLT_MAX;
+    }
+    
+    UCharImageType::RegionType region = img->GetLargestPossibleRegion();
+    itk::ImageRegionConstIteratorWithIndex< UCharImageType >
+        it (img,  region);
+
+    for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
+        unsigned char c = it.Get();
+        if (!c) {
+            continue;
+        }
+        /* If voxel is non-zero, loop through the eight corners of the 
+           voxels, find their position, and set bounding box to contain */
+        itk::ContinuousIndex<float,3> cidx = it.GetIndex();
+        for (int i = 0; i < 8; i++) {
+            itk::ContinuousIndex<float,3> cidx_corner = cidx;
+            cidx_corner[0] += (i % 2) - 0.5;
+            cidx_corner[1] += ((i / 2) % 2) - 0.5;
+            cidx_corner[2] += (i / 4) - 0.5;
+            FloatPoint3DType point;
+            img->TransformContinuousIndexToPhysicalPoint (cidx_corner, point);
+            for (int d = 0; d < 3; d++) {
+                if (point[d] < bbox[2*d+0]) {
+                    bbox[2*d+0] = point[d];
+                }
+                if (point[d] > bbox[2*d+1]) {
+                   bbox[2*d+1] = point[d];
+                }
+            }
+        }
+    }
+}
diff --git a/src/plastimatch/base/dcmtk_uid.h b/src/plastimatch/base/itk_bbox.h
old mode 100755
new mode 100644
similarity index 64%
copy from src/plastimatch/base/dcmtk_uid.h
copy to src/plastimatch/base/itk_bbox.h
index ed97eb0..9aa97bc
--- a/src/plastimatch/base/dcmtk_uid.h
+++ b/src/plastimatch/base/itk_bbox.h
@@ -1,12 +1,13 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef __dcmtk_uid_h__
-#define __dcmtk_uid_h__
+#ifndef _itk_bbox_h_
+#define _itk_bbox_h_
 
 #include "plmbase_config.h"
+#include "itk_image_type.h"
 
-PLMBASE_API char*
-dcmtk_uid (char *uid, const char *uid_root);
+PLMBASE_API void
+itk_bbox (const UCharImageType::Pointer img, float *bbox);
 
 #endif
diff --git a/src/plastimatch/base/itk_dicom_load.cxx b/src/plastimatch/base/itk_dicom_load.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_dicom_load.h b/src/plastimatch/base/itk_dicom_load.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_dicom_save.cxx b/src/plastimatch/base/itk_dicom_save.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_dicom_save.h b/src/plastimatch/base/itk_dicom_save.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_directions.cxx b/src/plastimatch/base/itk_directions.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_directions.h b/src/plastimatch/base/itk_directions.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_image_clone.cxx b/src/plastimatch/base/itk_image_clone.cxx
index ca771b3..ecacb31 100644
--- a/src/plastimatch/base/itk_image_clone.cxx
+++ b/src/plastimatch/base/itk_image_clone.cxx
@@ -7,11 +7,10 @@
 #include "itkImageDuplicator.h"
 
 #include "itk_image_clone.h"
+#include "itk_image_create.h"
 #include "itk_image_type.h"
+#include "plm_image_header.h"
 
-/* -----------------------------------------------------------------------
-   Casting image types
-   ----------------------------------------------------------------------- */
 template<class T> 
 T
 itk_image_clone (T image)
@@ -25,6 +24,23 @@ itk_image_clone (T image)
     return duplicator->GetOutput();
 }
 
+template<class T> 
+T
+itk_image_clone_empty (T image)
+{
+    T img = T::ObjectType::New ();
+    img->SetOrigin (image->GetOrigin());
+    img->SetSpacing (image->GetSpacing());
+    img->SetDirection (image->GetDirection());
+    img->SetRegions (image->GetLargestPossibleRegion());
+    img->Allocate ();
+    img->FillBuffer (static_cast<typename T::ObjectType::PixelType>(0));
+
+    return img;
+}
+
 
 /* Explicit instantiations */
 template PLMBASE_API FloatImageType::Pointer itk_image_clone (FloatImageType::Pointer);
+
+template PLMBASE_API UCharImageType::Pointer itk_image_clone_empty (UCharImageType::Pointer);
diff --git a/src/plastimatch/base/itk_image_clone.h b/src/plastimatch/base/itk_image_clone.h
index 2995214..6a13ab2 100644
--- a/src/plastimatch/base/itk_image_clone.h
+++ b/src/plastimatch/base/itk_image_clone.h
@@ -11,4 +11,6 @@
    Function prototypes
    ----------------------------------------------------------------------- */
 template<class T> PLMBASE_API T itk_image_clone (T image);
+template<class T> PLMBASE_API T itk_image_clone_empty (T image);
+
 #endif
diff --git a/src/plastimatch/base/itk_image_load_char.cxx b/src/plastimatch/base/itk_image_load_char.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_image_load_double.cxx b/src/plastimatch/base/itk_image_load_double.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_image_type.h b/src/plastimatch/base/itk_image_type.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_metadata.cxx b/src/plastimatch/base/itk_metadata.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_metadata.h b/src/plastimatch/base/itk_metadata.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_pointset.cxx b/src/plastimatch/base/itk_pointset.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/itk_pointset.h b/src/plastimatch/base/itk_pointset.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/parameter_parser.cxx b/src/plastimatch/base/parameter_parser.cxx
index 7cf55c8..4097e95 100644
--- a/src/plastimatch/base/parameter_parser.cxx
+++ b/src/plastimatch/base/parameter_parser.cxx
@@ -18,6 +18,7 @@
 
 Parameter_parser::Parameter_parser () {
     key_regularization = true;
+    default_index = "";
 }
 
 Plm_return_code
@@ -69,16 +70,10 @@ Parameter_parser::parse_config_string (
         /* Process "key=value" */
         std::string key;
         std::string val;
-        size_t key_loc = buf.find ("=");
-        if (key_loc == std::string::npos) {
-            key = buf;
-            val = "";
-        } else {
-            key = buf.substr (0, key_loc);
-            val = buf.substr (key_loc+1);
+        if (!split_key_val (buf, key, val)) {
+            lprintf ("Parse error: %s\n", buf_ori.c_str());
+            return PLM_ERROR;
         }
-        key = string_trim (key);
-        val = string_trim (val);
 
         /* Key becomes lowercase, with "_" & "-" unified */
         if (this->key_regularization) {
@@ -96,10 +91,21 @@ Parameter_parser::parse_config_string (
             continue;
         }
 
-        Plm_return_code rc = this->set_key_value (section, key, val);
+        /* Handle key[index]=value */
+        std::string array;
+        std::string index;
+        if (!split_array_index (key, array, index)) {
+            lprintf ("Parse error: %s\n", buf_ori.c_str());
+            return PLM_ERROR;
+        }
+        if (index == "") {
+            index = default_index;
+        }
+        
+        Plm_return_code rc = this->set_key_value (section, array, index, val);
         if (rc != PLM_SUCCESS) {
             lprintf ("Parse error: %s\n", buf_ori.c_str());
-            return rc;
+            return PLM_ERROR;
         }
     }
 
@@ -117,6 +123,20 @@ Parameter_parser::enable_key_regularization (
     this->key_regularization = enable;
 }
 
+void 
+Parameter_parser::set_default_index (
+    std::string& default_index)
+{
+    this->default_index = default_index;
+}
+
+void 
+Parameter_parser::set_default_index (
+    const char *default_index)
+{
+    this->default_index = std::string(default_index);
+}
+
 Plm_return_code
 Parameter_parser::parse_config_string (
     const std::string& config_string
diff --git a/src/plastimatch/base/parameter_parser.h b/src/plastimatch/base/parameter_parser.h
index f21bbdc..5725abe 100644
--- a/src/plastimatch/base/parameter_parser.h
+++ b/src/plastimatch/base/parameter_parser.h
@@ -7,11 +7,17 @@
 #include "plmbase_config.h"
 #include "plm_return_code.h"
 
+/*! \brief 
+ * The Parameter_parser class is an abstract base class which is used 
+ * to parse ini-style file formats that control the registration, mabs, 
+ * and dose calculation codes.
+ */
 class PLMBASE_API Parameter_parser {
 public:
     Parameter_parser ();
 public:
     bool key_regularization;
+    std::string default_index;
 public:
     /* Callbacks */
     virtual Plm_return_code begin_section (
@@ -21,6 +27,7 @@ public:
     virtual Plm_return_code set_key_value (
         const std::string& section, 
         const std::string& key, 
+        const std::string& index, 
         const std::string& val) = 0;
 
     /* Pass in "true" to enable key regularization, or "false" to 
@@ -29,6 +36,11 @@ public:
         bool enable
     );
 
+    /*! \brief Choose what index is passed to set_key_value() 
+      when no index is found in the file.  Default is "". */
+    void set_default_index (std::string& default_index);
+    void set_default_index (const char *default_index);
+
     /* Return zero if config string is correctly parsed */
     Plm_return_code parse_config_string (
         const char* config_string
diff --git a/src/plastimatch/base/plm_file_format.cxx b/src/plastimatch/base/plm_file_format.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/plm_file_format.h b/src/plastimatch/base/plm_file_format.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/plm_image_header.cxx b/src/plastimatch/base/plm_image_header.cxx
index 8c3cfd7..7ae4ef3 100644
--- a/src/plastimatch/base/plm_image_header.cxx
+++ b/src/plastimatch/base/plm_image_header.cxx
@@ -82,6 +82,12 @@ Plm_image_header::Plm_image_header (const Volume_header& vh)
     this->set (vh);
 }
 
+Plm_image_header::Plm_image_header (const Volume::Pointer& vol) 
+{
+    d_ptr = new Plm_image_header_private;
+    this->set (vol);
+}
+
 Plm_image_header::Plm_image_header (const Volume& vol) 
 {
     d_ptr = new Plm_image_header_private;
@@ -322,6 +328,13 @@ Plm_image_header::set_from_volume_header (const Volume_header& vh)
 }
 
 void
+Plm_image_header::set (const Volume::Pointer& vol)
+{
+    this->set_from_gpuit (vol->dim, vol->origin,
+	vol->spacing, vol->direction_cosines);
+}
+
+void
 Plm_image_header::set (const Volume& vol)
 {
     this->set_from_gpuit (vol.dim, vol.origin,
diff --git a/src/plastimatch/base/plm_image_header.h b/src/plastimatch/base/plm_image_header.h
index 871d562..dfeb880 100644
--- a/src/plastimatch/base/plm_image_header.h
+++ b/src/plastimatch/base/plm_image_header.h
@@ -42,6 +42,7 @@ public:
     Plm_image_header (const Plm_image& pli);
     Plm_image_header (const Plm_image::Pointer& pli);
     Plm_image_header (const Volume_header& vh);
+    Plm_image_header (const Volume::Pointer& vol);
     Plm_image_header (const Volume& vol);
     Plm_image_header (const Volume* vol);
     Plm_image_header (Volume* vol);
@@ -86,6 +87,7 @@ public:
     void set_from_plm_image (const Plm_image::Pointer& pli);
     void set_from_volume_header (const Volume_header& vh);
     void set (const Volume_header& vh);
+    void set (const Volume::Pointer& vol);
     void set (const Volume& vol);
     void set (const Volume* vol);
     void set (const RegionType& region, const OriginType& origin,
diff --git a/src/plastimatch/base/plm_image_type.cxx b/src/plastimatch/base/plm_image_type.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/proj_image.cxx b/src/plastimatch/base/proj_image.cxx
index f076da8..da40555 100644
--- a/src/plastimatch/base/proj_image.cxx
+++ b/src/plastimatch/base/proj_image.cxx
@@ -146,7 +146,7 @@ raw_save (Proj_image *proj, const char* img_filename)
 {
     FILE* fp;
     
-    fp = fopen (img_filename, "wb");
+    fp = plm_fopen (img_filename, "wb");
     if (!fp) {
         fprintf (stderr, "Can't open file %s for write\n", img_filename);
         exit (-1);
@@ -212,7 +212,7 @@ pfm_save (Proj_image *proj, const char* img_filename)
     FILE* fp;
     
     make_parent_directories (img_filename);
-    fp = fopen (img_filename, "wb");
+    fp = plm_fopen (img_filename, "wb");
     if (!fp) {
         fprintf (stderr, "Can't open file %s for write\n", img_filename);
         exit (-1);
@@ -235,7 +235,7 @@ pgm_save (Proj_image *proj, const char* img_filename)
     int i;
     
     make_parent_directories (img_filename);
-    fp = fopen (img_filename, "wb");
+    fp = plm_fopen (img_filename, "wb");
     if (!fp) {
         fprintf (stderr, "Can't open file %s for write\n", img_filename);
         exit (-1);
diff --git a/src/plastimatch/base/proj_matrix.cxx b/src/plastimatch/base/proj_matrix.cxx
old mode 100644
new mode 100755
index 1cd1c17..790cd60
--- a/src/plastimatch/base/proj_matrix.cxx
+++ b/src/plastimatch/base/proj_matrix.cxx
@@ -140,8 +140,7 @@ Proj_matrix::set (
     const double* vup, 
     double sid, 
     const double* ic, 
-    const double* ps, 
-    const int* ires
+    const double* ps
 )
 {
     const int cols = 4;
@@ -151,7 +150,7 @@ Proj_matrix::set (
 
     vec3_copy (this->cam, cam);
     this->sid = sid;
-    this->sad = vec3_len (cam);
+    this->sad = vec3_dist (cam, tgt);
     this->ic[0] = ic[0];
     this->ic[1] = ic[1];
 
@@ -249,3 +248,19 @@ Proj_matrix::get_prt (
 {
     vec3_copy (prt, &this->extrinsic[0]);
 }
+
+void
+Proj_matrix::project_h (double* ij, const double* xyz) const
+{
+    mat43_mult_vec4 (ij, this->matrix, xyz);
+}
+
+void
+Proj_matrix::project (double* ij, const double* xyz) const
+{
+    ij[0] = vec3_dot(&this->matrix[0], xyz) + this->matrix[3];
+    ij[1] = vec3_dot(&this->matrix[4], xyz) + this->matrix[7];
+    double h = vec3_dot(&this->matrix[8], xyz) + this->matrix[11];
+    ij[0] = this->ic[0] + ij[0] / h;
+    ij[1] = this->ic[1] + ij[1] / h;
+}
diff --git a/src/plastimatch/base/proj_matrix.h b/src/plastimatch/base/proj_matrix.h
old mode 100644
new mode 100755
index 2ab757f..793b871
--- a/src/plastimatch/base/proj_matrix.h
+++ b/src/plastimatch/base/proj_matrix.h
@@ -34,11 +34,21 @@ public:
         const double* vup, 
         double sid, 
         const double* ic, 
-        const double* ps, 
-        const int* ires
+        const double* ps
     );
     void set (const std::string& s);
 
+    /* Project 3D coordinate xyz of cartesian space 
+       into 2D coordinate ij coordinate on projection plane.  
+       In this version, the inputs and outputs are homogenous, 
+       not cartesian. */
+    void project_h (double* ij, const double* xyz) const;
+    /* Project 3D coordinate xyz of cartesian space 
+       into 2D coordinate ij coordinate on projection plane.  
+       In this version, the inputs and outputs are cartesian, 
+       not homogenous. */
+    void project (double* ij, const double* xyz) const;
+
     void save (const char *fn);
     void debug ();
     Proj_matrix* clone ();
diff --git a/src/plastimatch/base/proj_volume.cxx b/src/plastimatch/base/proj_volume.cxx
old mode 100644
new mode 100755
index 9dd611d..e07f499
--- a/src/plastimatch/base/proj_volume.cxx
+++ b/src/plastimatch/base/proj_volume.cxx
@@ -40,9 +40,9 @@ public:
 public:
     Volume::Pointer vol;
     Proj_matrix *pmat;
-    int num_steps;
+    plm_long num_steps;
     double step_length;
-    int image_dim[2];
+    plm_long image_dim[2];
     double image_spacing[2];
     double clipping_dist[2];
     double nrm[3];
@@ -78,7 +78,7 @@ Proj_volume::set_geometry (
     const double iso[3],           // position of isocenter (mm)
     const double vup[3],           // dir to "top" of projection plane
     double sid,                    // dist from proj plane to source (mm)
-    const int image_dim[2],        // resolution of image
+    const plm_long image_dim[2],   // resolution of image
     const double image_center[2],  // image center (pixels)
     const double image_spacing[2], // pixel size (mm)
     const double clipping_dist[2], // dist from src to clipping planes (mm)
@@ -90,8 +90,8 @@ Proj_volume::set_geometry (
     /* save input settings */
     d_ptr->image_dim[0] = image_dim[0];
     d_ptr->image_dim[1] = image_dim[1];
-	d_ptr->image_spacing[0] = image_spacing[0];
-	d_ptr->image_spacing[1] = image_spacing[1];
+    d_ptr->image_spacing[0] = image_spacing[0];
+    d_ptr->image_spacing[1] = image_spacing[1];
     d_ptr->src[0] = src[0];
     d_ptr->src[1] = src[1];
     d_ptr->src[2] = src[2];
@@ -107,8 +107,7 @@ Proj_volume::set_geometry (
         vup, 
         sid, 
         image_center,
-        image_spacing,
-        image_dim
+        image_spacing
     );
 
     /* populate aperture orientation unit vectors */
@@ -161,7 +160,7 @@ Proj_volume::set_clipping_dist (const double clipping_dist[2])
 {
     d_ptr->clipping_dist[0] = clipping_dist[0];
     d_ptr->clipping_dist[1] = clipping_dist[1];
-    d_ptr->num_steps = (int) ceil (
+    d_ptr->num_steps = (plm_long) ceil (
         (clipping_dist[1] - clipping_dist[0]) / d_ptr->step_length);
 }
 
@@ -179,18 +178,24 @@ Proj_volume::allocate ()
         direction_cosines, PT_FLOAT, 1);
 }
 
-const int*
+const plm_long*
 Proj_volume::get_image_dim ()
 {
     return d_ptr->image_dim;
 }
 
-int
+plm_long
 Proj_volume::get_image_dim (int dim)
 {
     return d_ptr->image_dim [dim];
 }
 
+plm_long
+Proj_volume::get_num_steps ()
+{
+    return d_ptr->num_steps;
+}
+
 const double*
 Proj_volume::get_incr_c ()
 {
@@ -217,7 +222,7 @@ Proj_volume::get_proj_matrix ()
 }
 
 const double*
-Proj_volume::get_src ()
+Proj_volume::get_src () const
 {
     return d_ptr->src;
 }
@@ -235,7 +240,7 @@ Proj_volume::get_clipping_dist ()
 }
 
 double
-Proj_volume::get_step_length ()
+Proj_volume::get_step_length () const
 {
     return d_ptr->step_length;
 }
@@ -259,6 +264,18 @@ Proj_volume::get_vol () const
 }
 
 void
+Proj_volume::project_h (double* ij, const double* xyz) const
+{
+    d_ptr->pmat->project_h (ij, xyz);
+}
+
+void
+Proj_volume::project (double* ij, const double* xyz) const
+{
+    d_ptr->pmat->project (ij, xyz);
+}
+
+void
 Proj_volume::save_img (const char *filename)
 {
     Plm_image(d_ptr->vol).save_image(filename);
@@ -355,24 +372,24 @@ Proj_volume::load_header (const char* filename)
             break;
         }
 
-        std::string tag, val;
-        if (!split_tag_val (line, tag, val)) {
+        if (line.find('=') == std::string::npos) {
             /* No "=" found. */
             break;
         }
 
+        int a, b;
+        float f, g;
         int rc;
-        rc = sscanf (line.c_str(), "num_steps = %d\n", &d_ptr->num_steps);
+        rc = sscanf (line.c_str(), "num_steps = %d\n", &a);
+        d_ptr->num_steps = a;
         if (rc == 1) continue;
 
-        float f, g;
         rc = sscanf (line.c_str(), "step_length = %f\n", &f);
         if (rc == 1) {
             d_ptr->step_length = f;
             continue;
         }
 
-        int a, b;
         rc = sscanf (line.c_str(), "image_dim = %d %d\n", &a, &b);
         if (rc == 3) {
             d_ptr->image_dim[0] = a;
diff --git a/src/plastimatch/base/proj_volume.h b/src/plastimatch/base/proj_volume.h
old mode 100644
new mode 100755
index 2b43a74..a62e419
--- a/src/plastimatch/base/proj_volume.h
+++ b/src/plastimatch/base/proj_volume.h
@@ -6,6 +6,7 @@
 
 #include "plmbase_config.h"
 #include <string>
+#include "plm_int.h"
 
 class Proj_matrix;
 class Proj_volume_private;
@@ -30,23 +31,24 @@ public:
         const double iso[3],           // position of isocenter (mm)
         const double vup[3],           // dir to "top" of projection plane
         double sid,                    // dist from proj plane to source (mm)
-        const int image_dim[2],        // resolution of image
+        const plm_long image_dim[2],   // resolution of image
         const double image_center[2],  // image center (pixels)
         const double image_spacing[2], // pixel size (mm)
         const double clipping_dist[2], // dist from src to clipping planes (mm)
         const double step_length       // spacing between planes
     );
     void set_clipping_dist (const double clipping_dist[2]);
-    const int* get_image_dim ();
-    int get_image_dim (int dim);
+    const plm_long* get_image_dim ();
+    plm_long get_image_dim (int dim);
+    plm_long get_num_steps ();
     const double* get_incr_c ();
     const double* get_incr_r ();
     Proj_matrix *get_proj_matrix ();
     const double* get_nrm ();
-    const double* get_src ();
+    const double* get_src () const;
     const double* get_iso ();
     const double* get_clipping_dist();
-    double get_step_length ();
+    double get_step_length () const;
     const double* get_ul_room ();
     Volume *get_vol ();
     const Volume *get_vol () const;
@@ -66,6 +68,17 @@ public:
     void load_projv (const char* filename);
     void load_projv (const std::string& filename);
 
+    /* Project 3D coordinate xyz of cartesian space 
+       into 2D coordinate ij coordinate on projection plane.  
+       In this version, the inputs and outputs are homogenous, 
+       not cartesian. */
+    void project_h (double* ij, const double* xyz) const;
+    /* Project 3D coordinate xyz of cartesian space 
+       into 2D coordinate ij coordinate on projection plane.  
+       In this version, the inputs and outputs are cartesian, 
+       not homogenous. */
+    void project (double* ij, const double* xyz) const;
+
     void debug ();
 };
 
diff --git a/src/plastimatch/base/pwlut.cxx b/src/plastimatch/base/pwlut.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/pwlut.h b/src/plastimatch/base/pwlut.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/ray_trace.h b/src/plastimatch/base/ray_trace.h
index 7cea27e..df2cc6e 100644
--- a/src/plastimatch/base/ray_trace.h
+++ b/src/plastimatch/base/ray_trace.h
@@ -15,10 +15,15 @@ class Volume_limit;
 #define DRR_PLANE_RAY_TOLERANCE 1e-8
 #define DRR_STRIDE_TOLERANCE 1e-10
 #define DRR_HUGE_DOUBLE 1e10
-#define DRR_LEN_TOLERANCE 1e-6
 #define DRR_TOPLANE_TOLERANCE 1e-7
 #define DRR_BOUNDARY_TOLERANCE 1e-6
 
+/* GCS FIX: "Temporary" fix against overshooting image boundary 
+   when ray tracing.  This fix should be replaced with something 
+   more robust, such as an explicit bounds check. */
+//#define DRR_LEN_TOLERANCE 1e-6
+#define DRR_LEN_TOLERANCE 2e-5
+
 #define DRR_MSD_NUM_BINS 60
 
 #define DRR_PREPROCESS_ATTENUATION 1
diff --git a/src/plastimatch/base/ray_trace_uniform.cxx b/src/plastimatch/base/ray_trace_uniform.cxx
index aaeca65..38fc824 100644
--- a/src/plastimatch/base/ray_trace_uniform.cxx
+++ b/src/plastimatch/base/ray_trace_uniform.cxx
@@ -33,9 +33,6 @@ ray_trace_uniform (
     double ip2[3];
     double phy_step[3];
 
-    int ai[3]={0,0,0};
-    double frac[3]={0.0, 0.0, 0.0};
-
     float pix_density;
     double pt;  
     double rlen;
@@ -54,7 +51,6 @@ ray_trace_uniform (
     if (!volume_limit_clip_segment (vol_limit, ip1, ip2, ip1in, ip2in)) {
 	return;
     }
-	
 
     ps[0] = vol->spacing[0];
     ps[1] = vol->spacing[1];
@@ -80,8 +76,6 @@ ray_trace_uniform (
         ipx[1] = ip1[1] + phy_step[1] * z;
         ipx[2] = ip1[2] + phy_step[2] * z;
 
-        // NEW VERSION - Compute CT volume indices and their fraction @ point + interpolation
-
         mijk[0] = (float) ((ipx[0] - vol->origin[0])/ps[0]);
         mijk[1] = (float) ((ipx[1] - vol->origin[1])/ps[1]);
         mijk[2] = (float) ((ipx[2] - vol->origin[2])/ps[2]);
diff --git a/src/plastimatch/base/rpl_volume.cxx b/src/plastimatch/base/rpl_volume.cxx
old mode 100644
new mode 100755
index 90c62e2..412eb8f
--- a/src/plastimatch/base/rpl_volume.cxx
+++ b/src/plastimatch/base/rpl_volume.cxx
@@ -35,6 +35,27 @@
 static bool global_debug = false;
 #endif
 
+//20140827_YKP
+//col0 = HU, col1 = Relative stopping power
+//Table: XiO, ctedproton 2007 provided by Yoost
+extern const double lookup_PrSTPR_XiO_MGH[][2] ={
+    -1000.0,    0.01,
+    0.0,        1.0,
+    40.0,       1.04,
+    1000.0,     1.52,
+    2000.0,     2.02,
+    3000.0,     2.55,
+};
+
+extern const double lookup_PrSTPR_XiO_MGH[][2];
+
+static void rpl_callback_accum (
+    void *callback_data, size_t vox_index, 
+    double vox_len, float vox_value);
+static void rpl_callback_sample (
+    void *callback_data, size_t vox_index, 
+    double vox_len, float vox_value);
+
 static void rpl_ray_trace_callback_ct_density (
     void *callback_data, 
     size_t vox_index, 
@@ -77,14 +98,12 @@ public:
     Plm_image::Pointer ct;
     Volume_limit ct_limit;
     Ray_data *ray_data;
+    // Clipping distances are computed from aperture plane, not from source
     double front_clipping_dist;
     double back_clipping_dist;
-
     Aperture::Pointer aperture;
-    double max_wed;
-    double min_wed;
-    double min_distance_target;
-
+    Rpl_volume_ray_trace_start rvrts;
+    
 public:
     Rpl_volume_private () {
         proj_vol = new Proj_volume;
@@ -93,9 +112,7 @@ public:
         front_clipping_dist = DBL_MAX;
         back_clipping_dist = -DBL_MAX;
         aperture = Aperture::New ();
-        min_wed = 0.;
-        max_wed = 0.;
-        min_distance_target = 0.;
+        rvrts = RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION;
     }
     ~Rpl_volume_private () {
         delete proj_vol;
@@ -119,7 +136,7 @@ Rpl_volume::set_geometry (
     const double iso[3],           // position of isocenter (mm)
     const double vup[3],           // dir to "top" of projection plane
     double sid,                    // dist from proj plane to source (mm)
-    const int image_dim[2],        // resolution of image
+    const plm_long image_dim[2],   // resolution of image
     const double image_center[2],  // image center (pixels)
     const double image_spacing[2], // pixel size (mm)
     const double step_length       // spacing between planes
@@ -146,6 +163,27 @@ Rpl_volume::set_geometry (
 }
 
 void 
+Rpl_volume::clone_geometry (const Rpl_volume *rv)
+{
+    this->set_geometry (
+        rv->d_ptr->proj_vol->get_src(),
+        rv->d_ptr->proj_vol->get_iso(),
+        rv->get_aperture()->vup,
+        rv->get_aperture()->get_distance(),
+        rv->get_aperture()->get_dim(),
+        rv->get_aperture()->get_center(),
+        rv->get_aperture()->get_spacing(),
+        rv->d_ptr->proj_vol->get_step_length());
+}
+
+void
+Rpl_volume::set_ray_trace_start (Rpl_volume_ray_trace_start rvrts)
+{
+    printf ("Setting RVRTS = %d\n", (int) rvrts);
+    d_ptr->rvrts = rvrts;
+}
+
+void 
 Rpl_volume::set_ct_volume (Plm_image::Pointer& ct_volume)
 {
     d_ptr->ct = ct_volume;
@@ -172,18 +210,30 @@ Rpl_volume::set_aperture (Aperture::Pointer& ap)
     d_ptr->aperture = ap;
 }
 
+const plm_long*
+Rpl_volume::get_image_dim ()
+{
+    return d_ptr->proj_vol->get_image_dim();
+}
+
+plm_long
+Rpl_volume::get_num_steps ()
+{
+    return d_ptr->proj_vol->get_num_steps();
+}
+
 /* 1D interpolation */
 double
-Rpl_volume::get_rgdepth (
-    int ap_ij[2],       /* I: aperture index */
-    double dist         /* I: distance from aperture in mm */
-)
+Rpl_volume::get_value (
+    plm_long ap_ij[2],       /* I: aperture index */
+    double dist              /* I: distance from aperture in mm */
+) const
 {
     plm_long idx1, idx2;
     plm_long ijk[3];
     double rg1, rg2, rgdepth, frac;
-    Proj_volume *proj_vol = this->get_proj_volume ();
-    Volume *vol = this->get_vol();
+    const Proj_volume *proj_vol = this->get_proj_volume ();
+    const Volume *vol = this->get_vol();
     float* d_img = (float*) vol->img;
 
     if (dist < 0) {
@@ -223,13 +273,13 @@ Rpl_volume::get_rgdepth (
 
 /* 3D interpolation */
 double
-Rpl_volume::get_rgdepth (
+Rpl_volume::get_value (
     double ap_ij[2],    /* I: aperture index */
     double dist         /* I: distance from aperture in mm */
-)
+) const
 {
-    Proj_volume *proj_vol = this->get_proj_volume ();
-    Volume *vol = this->get_vol();
+    const Proj_volume *proj_vol = this->get_proj_volume ();
+    const Volume *vol = this->get_vol();
 
     if (dist < 0) {
         return 0.0;
@@ -246,17 +296,17 @@ Rpl_volume::get_rgdepth (
 
 /* Lookup radiological path length to a voxel in world space */
 double
-Rpl_volume::get_rgdepth (
+Rpl_volume::get_value (
     const double* ct_xyz         /* I: location of voxel in world space */
-)
+) const
 {
     int ap_ij[2], ap_idx;
     double ap_xy[3];
     double dist, rgdepth = 0.;
-    int debug = 0;
+    bool debug = false;
 
     /* A couple of abbreviations */
-    const int *ires = d_ptr->proj_vol->get_image_dim();
+    const plm_long *ires = d_ptr->proj_vol->get_image_dim();
     Proj_matrix *pmat = d_ptr->proj_vol->get_proj_matrix();
 
     if (debug) {
@@ -264,9 +314,7 @@ Rpl_volume::get_rgdepth (
     }
 
     /* Back project the voxel to the aperture plane */
-    mat43_mult_vec3 (ap_xy, pmat->matrix, ct_xyz);
-    ap_xy[0] = pmat->ic[0] + ap_xy[0] / ap_xy[2];
-    ap_xy[1] = pmat->ic[1] + ap_xy[1] / ap_xy[2];
+    d_ptr->proj_vol->project (ap_xy, ct_xyz);
 
     /* Make sure value is not inf or NaN */
     if (!is_number (ap_xy[0]) || !is_number (ap_xy[1])) {
@@ -287,9 +335,8 @@ Rpl_volume::get_rgdepth (
         return -1;
     }
 
-    ap_idx = ap_ij[1] * ires[0] + ap_ij[0];
-
     /* Look up pre-computed data for this ray */
+    ap_idx = ap_ij[1] * ires[0] + ap_ij[0];
     Ray_data *ray_data = &d_ptr->ray_data[ap_idx];
     double *ap_xyz = ray_data->p2;
 
@@ -300,11 +347,16 @@ Rpl_volume::get_rgdepth (
     /* Compute distance from aperture to voxel */
     dist = vec3_dist (ap_xyz, ct_xyz);
 
-    /* Subtract off standoff distance */
-    dist -= d_ptr->front_clipping_dist;
+    // Subtract off standoff distance.  Nearest neighbor aperture index
+    // is used for this calculation.
+    if (d_ptr->rvrts == RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION) {
+        dist -= ray_data->front_dist;
+    } else {
+        dist -= d_ptr->front_clipping_dist;
+    }
 
     /* Retrieve the radiographic depth */
-    rgdepth = this->get_rgdepth (ap_xy, dist);
+    rgdepth = this->get_value (ap_xy, dist);
 
     return rgdepth;
 }
@@ -334,16 +386,17 @@ Volume_limit* Rpl_volume::get_ct_limit()
     return &d_ptr->ct_limit;
 }
 
-void Rpl_volume::set_ray(Ray_data *ray)
+void Rpl_volume::set_ray_data (Ray_data *ray)
 {
     d_ptr->ray_data = ray;
 }
-Ray_data* Rpl_volume::get_Ray_data()
+
+Ray_data* Rpl_volume::get_ray_data()
 {
     return d_ptr->ray_data;
 }
 
-void Rpl_volume::set_front_clipping_plane(double front_clip)
+void Rpl_volume::set_front_clipping_plane (double front_clip)
 {
     d_ptr->front_clipping_dist = front_clip;
 }
@@ -357,33 +410,16 @@ void Rpl_volume::set_back_clipping_plane(double back_clip)
 {
     d_ptr->back_clipping_dist = back_clip;
 }
+
 double Rpl_volume::get_back_clipping_plane() const
 {
     return d_ptr->back_clipping_dist;
 }
 
-void 
-Rpl_volume::set_minimum_distance_target(double min)
-{
-    d_ptr->min_distance_target = min;
-}
-	
-double 
-Rpl_volume::get_minimum_distance_target()
-{
-    return d_ptr->min_distance_target;
-}
-
 double
-Rpl_volume::get_max_wed ()
+Rpl_volume::get_step_length () const
 {
-    return d_ptr->max_wed;
-}
-
-double
-Rpl_volume::get_min_wed ()
-{
-    return d_ptr->min_wed;
+    return d_ptr->proj_vol->get_step_length ();
 }
 
 void 
@@ -393,14 +429,9 @@ Rpl_volume::compute_ray_data ()
     Proj_volume *proj_vol = d_ptr->proj_vol;
     const double *src = proj_vol->get_src();
     const double *nrm = proj_vol->get_nrm();
-    const int *ires = d_ptr->proj_vol->get_image_dim();
+    const plm_long *ires = d_ptr->proj_vol->get_image_dim();
     Volume *ct_vol = d_ptr->ct->get_vol();
 
-    lprintf ("Proj vol:\n");
-    proj_vol->debug ();
-    lprintf ("Ref vol:\n");
-    ct_vol->debug ();
-
     /* Allocate data for each ray */
     if (d_ptr->ray_data) delete[] d_ptr->ray_data;
     d_ptr->ray_data = new Ray_data[ires[0]*ires[1]];
@@ -487,9 +518,15 @@ Rpl_volume::compute_ray_data ()
                 ray_data->front_dist = vec3_dist (p2, ip1);
             }
             if (ray_data->front_dist < d_ptr->front_clipping_dist) {
+#if defined (commentout)
                 /* GCS FIX.  This should not be here.  */
-                // - 0.001 mm to avoid the closest ray to intersect the volume with a step inferior to its neighbours. The minimal ray will be the only one to touch the volume when offset_step = 0.
+                // - 0.001 mm to avoid the closest ray to intersect
+                // the volume with a step inferior to its neighbours.
+                // The minimal ray will be the only one to touch
+                // the volume when offset_step = 0.
                 d_ptr->front_clipping_dist = ray_data->front_dist - 0.001;
+#endif
+                d_ptr->front_clipping_dist = ray_data->front_dist;
             }
 
             /* Compute distance to back intersection point, and set 
@@ -508,8 +545,101 @@ Rpl_volume::compute_ray_data ()
     }
 }
 
+void 
+Rpl_volume::compute_rpl (
+    bool use_aperture, Ray_trace_callback callback)
+{
+    /* A couple of abbreviations */
+    Proj_volume *proj_vol = d_ptr->proj_vol;
+    const double *src = proj_vol->get_src();
+    int ires[2];
+    ires[0] = d_ptr->proj_vol->get_image_dim (0);
+    ires[1] = d_ptr->proj_vol->get_image_dim (1);
+
+    unsigned char *ap_img = 0;
+    if (use_aperture && d_ptr->aperture->have_aperture_image()) {
+        Volume::Pointer ap_vol = d_ptr->aperture->get_aperture_volume ();
+        ap_img = (unsigned char*) ap_vol->img;
+    }
+    Volume *ct_vol = d_ptr->ct->get_vol();
+
+    /* Preprocess data by clipping against volume */
+    this->compute_ray_data ();
+
+    if (d_ptr->front_clipping_dist == DBL_MAX) {
+        lprintf ("Sorry, total failure intersecting volume\n");
+        return;
+    }
+
+    lprintf ("FPD = %f, BPD = %f\n", 
+        d_ptr->front_clipping_dist, d_ptr->back_clipping_dist);
+
+    /* Ahh.  Now we can set the clipping planes and allocate the 
+       actual volume. */
+    double clipping_dist[2] = {
+        d_ptr->front_clipping_dist, d_ptr->back_clipping_dist};
+    d_ptr->proj_vol->set_clipping_dist (clipping_dist);
+    d_ptr->proj_vol->allocate ();
+ 
+    /* Scan through the aperture -- second pass */
+    for (int r = 0; r < ires[1]; r++) {
+        for (int c = 0; c < ires[0]; c++) {
+
+            /* Compute index of aperture pixel */
+            plm_long ap_idx = r * ires[0] + c;
+
+            /* Make some aliases */
+            Ray_data *ray_data = &d_ptr->ray_data[ap_idx];
+
+            /* Compute intersection with front clipping plane */
+            vec3_scale3 (ray_data->cp, ray_data->ray, 
+                d_ptr->front_clipping_dist);
+            vec3_add2 (ray_data->cp, ray_data->p2);
+
+#if VERBOSE
+            global_debug = false;
+            if (r == 49 && (c == 49 || c == 50)) {
+                global_debug = true;
+            }
+            if (global_debug) {
+                printf ("Tracing ray (%d,%d)\n", r, c);
+            }
+#endif
+
+            /* Check if beamlet is inside aperture, if not 
+               we skip ray tracing */
+            if (ap_img && ap_img[r*ires[0]+c] == 0) {
+                continue;
+            }
+
+            this->rpl_ray_trace (
+                ct_vol,
+                ray_data,
+                callback,
+                &d_ptr->ct_limit,
+                src,
+                0,
+                ires
+            );
+        }
+    }
+}
+
+void 
+Rpl_volume::compute_rpl_sample (bool use_aperture)
+{
+    this->compute_rpl (use_aperture, rpl_callback_sample);
+}
+
+void 
+Rpl_volume::compute_rpl_accum (bool use_aperture)
+{
+    this->compute_rpl (use_aperture, rpl_callback_accum);
+}
+
 /* This function samples the CT into a RPL equivalent geometry.
    The rpl_volume should be in proj_wed format, not in proj_ct format. */
+/* GCS Note: Why do others call compute_ray_data(), but this one does not?*/
 void 
 Rpl_volume::compute_rpl_ct_density ()
 {
@@ -536,9 +666,6 @@ Rpl_volume::compute_rpl_ct_density ()
     
     /* Scan through the aperture -- second pass */
     for (int r = 0; r < ires[1]; r++) {
-
-        //if (r % 50 == 0) printf ("Row: %4d/%d\n", r, rows);
-
         for (int c = 0; c < ires[0]; c++) {
 
             /* Compute index of aperture pixel */
@@ -582,6 +709,7 @@ Rpl_volume::compute_rpl_ct_density ()
 }
 
 /* This function samples the CT in rpl geometry with HU units */
+/* GCS NOTE: It does not check the aperture */
 void 
 Rpl_volume::compute_rpl_HU ()
 {
@@ -640,6 +768,8 @@ Rpl_volume::compute_rpl_HU ()
     }
 }
 
+/* GCS Note: This is different from compute_rpl() functions.
+   It calls compute_ray_data(), allocates, and computes ray_data->cp.  */
 void 
 Rpl_volume::compute_rpl_void ()
 {
@@ -682,6 +812,7 @@ Rpl_volume::compute_rpl_void ()
     }
 }
 
+/* GCS Note: The rgc should be added after ray tracing */
 void 
 Rpl_volume::compute_rpl_range_length_rgc ()
 {
@@ -760,17 +891,19 @@ Rpl_volume::compute_rpl_range_length_rgc ()
     }
 }
 
+/* GCS NOTE: This also does not check the aperture */
 void 
 Rpl_volume::compute_rpl_PrSTRP_no_rgc ()
 {
-    int ires[2];
     /* A couple of abbreviations */
     Proj_volume *proj_vol = d_ptr->proj_vol;
     const double *src = proj_vol->get_src();
+    int ires[2];
     ires[0] = d_ptr->proj_vol->get_image_dim (0);
     ires[1] = d_ptr->proj_vol->get_image_dim (1);
 
     Volume *ct_vol = d_ptr->ct->get_vol();
+    
     /* Preprocess data by clipping against volume */
     this->compute_ray_data ();
 
@@ -783,12 +916,9 @@ Rpl_volume::compute_rpl_PrSTRP_no_rgc ()
 
     /* Ahh.  Now we can set the clipping planes and allocate the 
        actual volume. */
-
     double clipping_dist[2] = {
       d_ptr->front_clipping_dist, d_ptr->back_clipping_dist};
-
     d_ptr->proj_vol->set_clipping_dist (clipping_dist);
-
     d_ptr->proj_vol->allocate ();
 
     /* Scan through the aperture -- second pass */
@@ -815,6 +945,7 @@ Rpl_volume::compute_rpl_PrSTRP_no_rgc ()
                 printf ("Tracing ray (%d,%d)\n", r, c);
             }
 #endif
+
             this->rpl_ray_trace (
                 ct_vol,            /* I: CT volume */
                 ray_data,          /* I: Pre-computed data for this ray */
@@ -845,17 +976,17 @@ double Rpl_volume::compute_farthest_penetrating_ray_on_nrm(float range)
 
     for (int apert_idx = 0; apert_idx < dim[0] * dim[1]; apert_idx++)
     {
-        Ray_data* ray_data = (Ray_data*) &this->get_Ray_data()[apert_idx];
+        Ray_data* ray_data = (Ray_data*) &this->get_ray_data()[apert_idx];
         for (int s = 0; s < dim[2]; s++)
         {
             idx = s * dim[0] * dim[1] + apert_idx;
-			if (s == dim[2]-1 || dim[2] == 0)
-			{
-				max_dist = offset + (double) dim[2] * this->get_vol()->spacing[2];
-				printf("Warning: Range > ray_length in volume => Some rays might stop outside of the volume image.\n");
-				printf("position of the maximal range on the z axis: z = %lg\n", max_dist);
-				return max_dist;
-			}
+            if (s == dim[2]-1 || dim[2] == 0)
+            {
+                max_dist = offset + (double) dim[2] * this->get_vol()->spacing[2];
+                printf("Warning: Range > ray_length in volume => Some rays might stop outside of the volume image.\n");
+                printf("position of the maximal range on the z axis: z = %lg\n", max_dist);
+                return max_dist;
+            }
 
             if (img[idx] > range)
             {
@@ -907,14 +1038,14 @@ Rpl_volume::compute_proj_wed_volume (
     //each geometric distance should increase, due to divergence.
     const double base_dist = proj_vol->get_proj_matrix()->sid; //distance from source to aperture
   
-    const int *ires = proj_vol->get_image_dim();
+    const plm_long *ires = proj_vol->get_image_dim();
 
-    int ap_ij[2]; //ray index of rvol
+    plm_long ap_ij[2]; //ray index of rvol
     plm_long ap_idx = 0;  //ray number
     Ray_data *ray_data;
     double ray_ap[3]; //vector from src to ray intersection with ap plane
     double ray_ap_length; //length of vector from src to ray intersection with ap plane
-    double rglength; //length that we insert into get_rgdepth for each ray
+    double rglength; //length that we insert into get_value for each ray
 
     for (ap_ij[1] = 0; ap_ij[1] < ires[1]; ap_ij[1]++) {
         for (ap_ij[0] = 0; ap_ij[0] < ires[0]; ap_ij[0]++) {
@@ -933,7 +1064,7 @@ Rpl_volume::compute_proj_wed_volume (
 
             rglength = base_rg_dist*(ray_ap_length/base_dist);
 
-            proj_wed_vol_img[ap_idx] = (float) (this->get_rgdepth(ap_ij,rglength));
+            proj_wed_vol_img[ap_idx] = (float) (this->get_value(ap_ij,rglength));
       
         }
     }
@@ -950,7 +1081,7 @@ Rpl_volume::compute_wed_volume (
     float *rvol_img = (float*) rvol->img;
     float *in_vol_img = (float*) in_vol->img;
     float *wed_vol_img = (float*) wed_vol->img;
-    const int *ires = proj_vol->get_image_dim();
+    const plm_long *ires = proj_vol->get_image_dim();
 
     plm_long wijk[3];  /* Index within wed_volume */
 
@@ -968,8 +1099,6 @@ Rpl_volume::compute_wed_volume (
                 // printf ("DEBUGGING %d %d\n", ires[1], ires[0]);
                 // debug = true;
             }
-#if defined (commentout)
-#endif
 
 	    /* Nothing to do if ray misses volume */
             Ray_data *ray_data = &d_ptr->ray_data[ap_idx];
@@ -1080,7 +1209,7 @@ Rpl_volume::compute_dew_volume (
     const plm_long *dew_dim = dew_vol->dim; 
   
     //Get some parameters from the proj volume
-    const int *ires = proj_vol->get_image_dim();
+    const plm_long *ires = proj_vol->get_image_dim();
     const double *src = proj_vol->get_src();
     const double dist = proj_vol->get_proj_matrix()->sid; //distance from source to aperture
     double src_iso_vec[3];   //vector from source to isocenter
@@ -1116,7 +1245,7 @@ Rpl_volume::compute_dew_volume (
     double ray_end[3];
 
     plm_long wijk[3]; //index within wed_volume
-    int ap_ij[2]; //ray indox of rvol
+    plm_long ap_ij[2]; //ray indox of rvol
     plm_long dijk[3]; //Index within dew_volume
     plm_long didx; //image index within dew_volume
 
@@ -1237,14 +1366,13 @@ Rpl_volume::compute_dew_volume (
 
                     //Now look up the radiation length, using the provided function,
                     //knowing the ray and the length along it.
-                    ap_ij[0] = (int) ray_lookup[i][0];
-                    ap_ij[1] = (int) ray_lookup[i][1];
+                    ap_ij[0] = ray_lookup[i][0];
+                    ap_ij[1] = ray_lookup[i][1];
                     /* GCS FIX: I think the ray_lookup stuff is 
                        3D interpolation, should reduce this code to 
-                       use the 3D interpolated version of get_rgdepth() */
+                       use the 3D interpolated version of get_value() */
 
-                    ray_rad_len[i] = this->get_rgdepth (
-                        ap_ij, rad_depth_input);
+                    ray_rad_len[i] = this->get_value (ap_ij, rad_depth_input);
 
                     //Set each corner to background.
                     master_square[i/2][i%2] = background;
@@ -1299,123 +1427,6 @@ Rpl_volume::compute_dew_volume (
     }
 }
 
-void 
-Rpl_volume::apply_smearing_to_target(float smearing, std::vector <double>& map_min_distance, std::vector <double>& map_max_distance)
-{
-    printf("Apply smearing to the target.\nThe smearing width is defined at the minimum depth of the target.\n");
-    /* Create a structured element of the right size */
-    int strel_half_size[2];
-    int strel_size[2];
-
-    /* Found the min of the target to be sure the smearing (margins) at the minimal depth */
-    double min = DBL_MAX;
-    for (size_t i = 0; i < map_min_distance.size(); i++) {
-        if (map_min_distance[i] > 0 && map_min_distance[i] < min) {
-            min = map_min_distance[i];
-        }
-    }
-    if (min == DBL_MAX)
-    {
-        printf("***ERROR: Target depth min is null for each ray. Smearing not applied\n");
-        return;
-    }
-    d_ptr->min_distance_target = min + d_ptr->aperture->get_distance() + d_ptr->front_clipping_dist;
-
-
-    /* The smearing width is scaled to the aperture */
-    strel_half_size[0] = ROUND_INT(smearing * d_ptr->aperture->get_distance() / (d_ptr->min_distance_target * d_ptr->aperture->get_spacing()[0]));
-    strel_half_size[1] = ROUND_INT(smearing * d_ptr->aperture->get_distance() / (d_ptr->min_distance_target * d_ptr->aperture->get_spacing()[1]));
-
-    strel_size[0] = 1 + 2 * strel_half_size[0];
-    strel_size[1] = 1 + 2 * strel_half_size[1];
-    float smearing_ap = smearing * d_ptr->aperture->get_distance() / (min + d_ptr->aperture->get_distance() + d_ptr->front_clipping_dist);
-
-    int *strel = new int[strel_size[0]*strel_size[1]];
-    /* (rf, cf) center of the smearing */
-    for (int r = 0; r < strel_size[1]; r++) {
-        float rf = (float) (r - strel_half_size[1]) * d_ptr->aperture->get_spacing()[0];
-        for (int c = 0; c < strel_size[0]; c++) {
-            float cf = (float) (c - strel_half_size[0]) * d_ptr->aperture->get_spacing()[1];
-
-            int idx = r*strel_size[0] + c;
-
-            strel[idx] = 0;
-            if ((rf*rf + cf*cf) <= smearing_ap*smearing_ap) {
-                strel[idx] = 1;
-            }
-        }
-    }
-
-    /* Debugging information */
-    for (int r = 0; r < strel_size[1]; r++) {
-        for (int c = 0; c < strel_size[0]; c++) {
-            int idx = r*strel_size[0] + c;
-            printf ("%d ", strel[idx]);
-        }
-        printf ("\n");
-    }
-
-    /* Apply smear to target maps */
-    double distance_min;
-    double distance_max;
-    std::vector<double> min_distance_tmp (map_min_distance.size(), 0);
-    std::vector<double> max_distance_tmp (map_max_distance.size(), 0);
-
-    for (int ar = 0; ar < d_ptr->aperture->get_dim()[1]; ar++) {
-        for (int ac = 0; ac < d_ptr->aperture->get_dim()[0]; ac++) {
-            int aidx = ar * d_ptr->aperture->get_dim()[0] + ac;
-
-            /* Reset the limit values */
-            distance_min = DBL_MAX;
-            distance_max = 0;
-
-            for (int sr = 0; sr < strel_size[1]; sr++) {
-                int pr = ar + sr - strel_half_size[1];
-                if (pr < 0 || pr >= d_ptr->aperture->get_dim()[1]) {
-                    continue;
-                }
-                for (int sc = 0; sc < strel_size[0]; sc++) {
-                    int pc = ac + sc - strel_half_size[0];
-                    if (pc < 0 || pc >= d_ptr->aperture->get_dim()[0]) {
-                        continue;
-                    }
-
-                    int sidx = sr * strel_size[0] + sc;
-                    if (strel[sidx] == 0) {
-                        continue;
-                    }
-
-                    int pidx = pr * d_ptr->aperture->get_dim()[0] + pc;
-                    if (map_min_distance[pidx] > 0 && map_min_distance[pidx] < distance_min) {
-                        distance_min = map_min_distance[pidx];
-                    }
-                    if (map_max_distance[pidx] > distance_max) {
-                        distance_max = map_max_distance[pidx];
-                    }
-                }
-            }
-            if (distance_min == DBL_MAX)
-            {
-                min_distance_tmp[aidx] = 0;
-            }
-            else 
-            {
-                min_distance_tmp[aidx] = distance_min;
-            }
-            max_distance_tmp[aidx] = distance_max;
-        }
-    }
-
-    /* update the initial distance map */
-    for (size_t i = 0; i < map_min_distance.size(); i++) {
-        map_min_distance[i] = min_distance_tmp[i];
-        map_max_distance[i] = max_distance_tmp[i];
-    }
-
-    /* Clean up */
-    delete[] strel;
-}
-
 void
 Rpl_volume::compute_volume_aperture(Aperture::Pointer ap)
 {
@@ -1445,8 +1456,9 @@ Rpl_volume::compute_volume_aperture(Aperture::Pointer ap)
     }
 }
 
+// In this new version the range compensator is added later in the code depending on the algorithm
 void 
-Rpl_volume::apply_beam_modifiers () // In this new version the range compensator is added later in the code depending on the algorithm
+Rpl_volume::apply_beam_modifiers ()
 {
     Volume::Pointer ap_vol = d_ptr->aperture->get_aperture_volume ();
     unsigned char *ap_img = (unsigned char*) ap_vol->img;
@@ -1454,7 +1466,7 @@ Rpl_volume::apply_beam_modifiers () // In this new version the range compensator
     float *proj_img = (float*) proj_vol->img;
 
     /* For each ray in aperture */
-    const int *ires = d_ptr->proj_vol->get_image_dim();
+    const plm_long *ires = d_ptr->proj_vol->get_image_dim();
 
     printf ("ires = %d %d\n", ires[0], ires[1]);
     printf ("proj_vol dim = %d %d %d\n", (int) proj_vol->dim[0], 
@@ -1479,65 +1491,6 @@ Rpl_volume::apply_beam_modifiers () // In this new version the range compensator
     }
 }
 
-void 
-Rpl_volume::compute_beam_modifiers_passive_scattering (Volume *seg_vol)
-{
-    std::vector<double> min;
-    std::vector<double> max;
-    compute_beam_modifiers_core (seg_vol, false, 0, 0, 0, min, max);
-    return;
-}
-
-void 
-Rpl_volume::compute_beam_modifiers_active_scanning (Volume *seg_vol)
-{
-    std::vector<double> min;
-    std::vector<double> max;
-    compute_beam_modifiers_core (seg_vol, true, 0, 0, 0, min, max);
-    return;
-}
-
-void 
-Rpl_volume::compute_beam_modifiers_passive_scattering (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin)
-{
-    std::vector<double> min;
-    std::vector<double> max;
-    compute_beam_modifiers_core (seg_vol, false, smearing, proximal_margin, distal_margin, min, max);
-    return;
-}
-
-void 
-Rpl_volume::compute_beam_modifiers_passive_scattering_slicerRt (Plm_image::Pointer& plmTgt, float smearing, float proximal_margin, float distal_margin)
-{
-    std::vector<double> min;
-    std::vector<double> max;
-    compute_beam_modifiers_core_slicerRt (plmTgt, false, smearing, proximal_margin, distal_margin, min, max);
-    return;
-}
-
-void 
-Rpl_volume::compute_beam_modifiers_active_scanning (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin)
-{
-    std::vector<double> min;
-    std::vector<double> max;
-    compute_beam_modifiers_core (seg_vol, true, smearing, proximal_margin, distal_margin, min, max);
-    return;
-}
-
-void 
-Rpl_volume::compute_beam_modifiers_passive_scattering (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max)
-{
-    compute_beam_modifiers_core (seg_vol, false, smearing, proximal_margin, distal_margin, map_wed_min, map_wed_max);
-    return;
-}
-
-void 
-Rpl_volume::compute_beam_modifiers_active_scanning (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max)
-{
-    compute_beam_modifiers_core (seg_vol, true, smearing, proximal_margin, distal_margin, map_wed_min, map_wed_max);
-    return;
-}
-
 Volume* 
 Rpl_volume::get_vol ()
 {
@@ -1556,6 +1509,12 @@ Rpl_volume::get_proj_volume ()
     return d_ptr->proj_vol;
 }
 
+const Proj_volume* 
+Rpl_volume::get_proj_volume () const
+{
+    return d_ptr->proj_vol;
+}
+
 void
 Rpl_volume::save (const char *filename)
 {
@@ -1570,7 +1529,7 @@ Rpl_volume::save (const char *filename)
     if (d_ptr->ray_data) {
         std::string raydata_fn = fn_base + ".raydata";
         FILE *fp = plm_fopen (raydata_fn, "wb");
-        const int *ires = d_ptr->proj_vol->get_image_dim();
+        const plm_long *ires = d_ptr->proj_vol->get_image_dim();
         for (int r = 0; r < ires[1]; r++) {
             for (int c = 0; c < ires[0]; c++) {
                 int ap_idx = r * ires[0] + c;
@@ -1609,9 +1568,6 @@ Rpl_volume::save (const char *filename)
         d_ptr->ct_limit.dir[0],
         d_ptr->ct_limit.dir[1],
         d_ptr->ct_limit.dir[2]);
-    fprintf (fp, "min_wed = %g\n", d_ptr->min_wed);
-    fprintf (fp, "max_wed = %g\n", d_ptr->max_wed);
-    fprintf (fp, "min_distance_target = %g\n", d_ptr->min_distance_target);
     fclose (fp);
 }
 
@@ -1781,13 +1737,17 @@ Rpl_volume::rpl_ray_trace (
     cd.accum = rc_thk;
     cd.ires = ires;
 
-    /* Figure out how many steps to first step within volume */
-    cd.step_offset = 0;
-    ray_data->step_offset = cd.step_offset;
-
-    /* Find location of first step within volume */
-    double tmp[3];
+    // Figure out location of, and number of steps to first step within volume
     double first_loc[3];
+    if (d_ptr->rvrts == RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION) {
+        ray_data->step_offset = cd.step_offset = 0;
+    } else {
+        ray_data->step_offset
+            = cd.step_offset
+            = (int) floor (ray_data->front_dist - d_ptr->front_clipping_dist)
+            / d_ptr->proj_vol->get_step_length ();
+    }
+    double tmp[3];
     vec3_scale3 (tmp, ray_data->ray, 
         cd.step_offset * d_ptr->proj_vol->get_step_length ());
     vec3_add3 (first_loc, ray_data->p2, tmp);
@@ -1810,7 +1770,7 @@ Rpl_volume::rpl_ray_trace (
     ray_trace_uniform (
         ct_vol,                     // INPUT: CT volume
         vol_limit,                  // INPUT: CT volume bounding box
-        callback,                   // INPUT: step action cbFunction
+        callback,                   // INPUT: step action Function
         &cd,                        // INPUT: callback data
         first_loc,                  // INPUT: ray starting point
         ray_data->ip2,              // INPUT: ray ending point
@@ -1831,7 +1791,7 @@ Rpl_volume::rpl_ray_trace (
 
 static
 void
-rpl_ray_trace_callback_ct_HU (
+rpl_callback_accum (
     void *callback_data, 
     size_t vox_index, 
     double vox_len, 
@@ -1846,7 +1806,7 @@ rpl_ray_trace_callback_ct_HU (
     int ap_area = cd->ires[0] * cd->ires[1];
     size_t step_num = vox_index + cd->step_offset;
 
-    cd->accum = 0;
+    cd->accum += vox_len * vox_value;
 
 #if VERBOSE
     if (global_debug) {
@@ -1870,12 +1830,12 @@ rpl_ray_trace_callback_ct_HU (
         return;
     }
 
-    depth_img[ap_area*step_num + ap_idx] = vox_value;
+    depth_img[ap_area*step_num + ap_idx] = cd->accum;
 }
 
 static
 void
-rpl_ray_trace_callback_ct_density (
+rpl_callback_sample (
     void *callback_data, 
     size_t vox_index, 
     double vox_len, 
@@ -1914,12 +1874,12 @@ rpl_ray_trace_callback_ct_density (
         return;
     }
 
-    depth_img[ap_area*step_num + ap_idx] = compute_density_from_HU(vox_value);
+    depth_img[ap_area*step_num + ap_idx] = vox_value;
 }
 
 static
 void
-rpl_ray_trace_callback_PrSTPR (
+rpl_ray_trace_callback_ct_HU (
     void *callback_data, 
     size_t vox_index, 
     double vox_len, 
@@ -1934,7 +1894,7 @@ rpl_ray_trace_callback_PrSTPR (
     int ap_area = cd->ires[0] * cd->ires[1];
     size_t step_num = vox_index + cd->step_offset;
 
-    cd->accum += vox_len * compute_PrSTPR_from_HU (vox_value); //vox_value = CT_HU
+    cd->accum = 0;
 
 #if VERBOSE
     if (global_debug) {
@@ -1958,12 +1918,12 @@ rpl_ray_trace_callback_PrSTPR (
         return;
     }
 
-    depth_img[ap_area*step_num + ap_idx] = cd->accum;
+    depth_img[ap_area*step_num + ap_idx] = vox_value;
 }
 
 static
 void
-rpl_ray_trace_callback_range_length (
+rpl_ray_trace_callback_ct_density (
     void *callback_data, 
     size_t vox_index, 
     double vox_len, 
@@ -1978,7 +1938,7 @@ rpl_ray_trace_callback_range_length (
     int ap_area = cd->ires[0] * cd->ires[1];
     size_t step_num = vox_index + cd->step_offset;
 
-    cd->accum += vox_len * compute_density_from_HU (vox_value); //vox_value = CT_HU
+    cd->accum = 0;
 
 #if VERBOSE
     if (global_debug) {
@@ -2002,14 +1962,12 @@ rpl_ray_trace_callback_range_length (
         return;
     }
 
-    depth_img[ap_area*step_num + ap_idx] = cd->accum;
+    depth_img[ap_area*step_num + ap_idx] = compute_density_from_HU(vox_value);
 }
 
-//Added by YKPark. Relative stopping power-based water eq. path length. Valid for 20 MeV ~ 240 MeV proton beam
-//t_w = t_m * rel. density * SP ratio(m to w) = t_m*RSP
 static
 void
-rpl_ray_trace_callback_RSP (
+rpl_ray_trace_callback_PrSTPR (
     void *callback_data, 
     size_t vox_index, 
     double vox_len, 
@@ -2024,7 +1982,7 @@ rpl_ray_trace_callback_RSP (
     int ap_area = cd->ires[0] * cd->ires[1];
     size_t step_num = vox_index + cd->step_offset;
 
-    cd->accum += vox_len * compute_PrSTRP_XiO_MGH_weq_from_HU (vox_value); //vox_value = CT_HU
+    cd->accum += vox_len * compute_PrSTPR_from_HU (vox_value); //vox_value = CT_HU
 
 #if VERBOSE
     if (global_debug) {
@@ -2051,462 +2009,93 @@ rpl_ray_trace_callback_RSP (
     depth_img[ap_area*step_num + ap_idx] = cd->accum;
 }
 
+static
 void
-Rpl_volume::compute_beam_modifiers_core (Volume *seg_vol, bool active, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max)
-{
-    printf("Compute target distance limits...\n");
-    /* compute the target min and max distance (not wed!) map in the aperture */
-    compute_target_distance_limits (seg_vol, map_wed_min, map_wed_max);
-
-    printf("Apply smearing to the target...\n");
-    /* widen the min/max distance maps */
-    if (smearing > 0)
-    {
-        apply_smearing_to_target(smearing, map_wed_min, map_wed_max);
-    }
-
-    printf("Apply longitudinal margins...\n");
-    /* add the margins */
-    for (size_t i = 0; i < map_wed_min.size(); i++) {
-        map_wed_min[i] -= proximal_margin;
-        if (map_wed_min[i] < 0) {
-            map_wed_min[i] = 0;
-        }
-        if (map_wed_max[i] > 0) {
-            map_wed_max[i] += distal_margin;
-        }
-    }
-
-    printf("Compute max wed...\n");
-    /* compute wed limits from depth limits and compute max wed of the target + margins */
-    int idx = 0;
-    double max_wed = 0;
-    int i[2] = {0, 0};
-    for (i[0] = 0; i[0] < d_ptr->aperture->get_aperture_volume()->dim[0]; i[0]++){
-        for (i[1] = 0; i[1] < d_ptr->aperture->get_aperture_volume()->dim[1]; i[1]++){
-            idx = i[0] + i[1] * d_ptr->aperture->get_aperture_volume()->dim[0];
-            if (map_wed_max[idx] <= 0) 
-            {
-                continue;
-            }
-            map_wed_min[idx] = this->get_rgdepth(i, map_wed_min[idx]);
-            map_wed_max[idx] = this->get_rgdepth(i, map_wed_max[idx]);
-            if (map_wed_max[idx] > max_wed) {
-                max_wed = map_wed_max[idx];
-            }
-        }
-    }
-
-    printf("Compute the aperture...\n");
-    /* compute the aperture */
-    /* This assumes that dim & spacing are correctly set in aperture */
-    d_ptr->aperture->allocate_aperture_images ();
-
-    Volume::Pointer aperture_vol = d_ptr->aperture->get_aperture_volume ();
-    unsigned char *aperture_img = (unsigned char*) aperture_vol->img;
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if (map_wed_min[i] > 0) {
-            aperture_img[i] = 1;
-        }
-        else {
-            aperture_img[i] = 0;
-        }
-    }
-	
-    /* compute the range compensator if passive beam line -- PMMA range compensator */
-    Volume::Pointer range_comp_vol = d_ptr->aperture->get_range_compensator_volume ();
-    float *range_comp_img = (float*) range_comp_vol->img;
-	
-    if (active == false)
-    {
-        printf("Compute range compensator...\n");
-    }
-
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if (active == true)
-        {
-            range_comp_img[i] = 0;
-        }
-        else 
-        {
-            range_comp_img[i] = (max_wed - map_wed_max[i]) / (PMMA_STPR * PMMA_DENSITY);
-        }
-    }
-
-    /* compute the max/min wed of the entire target + margins + range_comp*/
-    double total_min_wed = 0;
-    double total_max_wed = 0;
-    // Max should be the same as the max in the target as for this ray rgcomp is null
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > total_max_wed) { // if active beam line, range comp is null
-            total_max_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i];
-        }
-    }
-    total_min_wed = total_max_wed;
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if ((range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > 0) && (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i] < total_min_wed)) {
-            total_min_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i];
-        }
-    }
-
-    printf("Max wed in the target is %lg mm.\n", total_max_wed);
-    printf("Min wed in the target is %lg mm.\n", total_min_wed);
-
-    /* Save these values in private data store */
-    d_ptr->max_wed = total_max_wed;
-    d_ptr->min_wed = total_min_wed;
-    return;
-}
-
-void
-Rpl_volume::compute_beam_modifiers_core_slicerRt (Plm_image::Pointer& plmTgt, bool active, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max)
+rpl_ray_trace_callback_range_length (
+    void *callback_data, 
+    size_t vox_index, 
+    double vox_len, 
+    float vox_value
+)
 {
-    printf("Compute target distance limits...\n");
-
-    /* compute the target min and max distance (not wed!) map in the aperture */
-    compute_target_distance_limits_slicerRt(plmTgt, map_wed_min, map_wed_max);
-
-    printf("Apply smearing to the target...\n");
-    /* widen the min/max distance maps */
-    if (smearing > 0)
-    {
-        apply_smearing_to_target(smearing, map_wed_min, map_wed_max);
-    }
-
-    printf("Apply longitudinal margins...\n");
-    /* add the margins */
-    for (size_t i = 0; i < map_wed_min.size(); i++) {
-        map_wed_min[i] -= proximal_margin;
-        if (map_wed_min[i] < 0) {
-            map_wed_min[i] = 0;
-        }
-        if (map_wed_max[i] > 0) {
-            map_wed_max[i] += distal_margin;
-        }
-    }
-
-    printf("Compute max wed...\n");
-    /* compute wed limits from depth limits and compute max wed of the target + margins */
-    int idx = 0;
-    double max_wed = 0;
-    int i[2] = {0, 0};
-    for (i[0] = 0; i[0] < d_ptr->aperture->get_aperture_volume()->dim[0]; i[0]++){
-        for (i[1] = 0; i[1] < d_ptr->aperture->get_aperture_volume()->dim[1]; i[1]++){
-            idx = i[0] + i[1] * d_ptr->aperture->get_aperture_volume()->dim[0];
-            if (map_wed_max[idx] <= 0) 
-            {
-                continue;
-            }
-            map_wed_min[idx] = this->get_rgdepth(i, map_wed_min[idx]);
-            map_wed_max[idx] = this->get_rgdepth(i, map_wed_max[idx]);
-            if (map_wed_max[idx] > max_wed) {
-                max_wed = map_wed_max[idx];
-            }
-        }
-    }
+    Callback_data *cd = (Callback_data *) callback_data;
+    Rpl_volume *rpl_vol = cd->rpl_vol;
+    Ray_data *ray_data = cd->ray_data;
+    float *depth_img = (float*) rpl_vol->get_vol()->img;
+    int ap_idx = ray_data->ap_idx;
+    int ap_area = cd->ires[0] * cd->ires[1];
+    size_t step_num = vox_index + cd->step_offset;
 
-    printf("Compute the aperture...\n");
-    /* compute the aperture */
-    /* This assumes that dim & spacing are correctly set in aperture */
-    d_ptr->aperture->allocate_aperture_images ();
+    cd->accum += vox_len * compute_density_from_HU (vox_value); //vox_value = CT_HU
 
-    Volume::Pointer aperture_vol = d_ptr->aperture->get_aperture_volume ();
-    unsigned char *aperture_img = (unsigned char*) aperture_vol->img;
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if (map_wed_min[i] > 0) {
-            aperture_img[i] = 1;
-        }
-        else {
-            aperture_img[i] = 0;
-        }
-    }
-	
-    /* compute the range compensator if passive beam line -- PMMA range compensator */
-    Volume::Pointer range_comp_vol = d_ptr->aperture->get_range_compensator_volume ();
-    float *range_comp_img = (float*) range_comp_vol->img;
-	
-    if (active == false)
-    {
-        printf("Compute range compensator...\n");
+#if VERBOSE
+    if (global_debug) {
+	printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, 
+	    vox_value, cd->accum);
+        printf ("dim = %d %d %d\n", 
+            (int) rpl_vol->get_vol()->dim[0],
+            (int) rpl_vol->get_vol()->dim[1],
+            (int) rpl_vol->get_vol()->dim[2]);
+        printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", 
+            ap_area, (int) ap_idx, vox_len);
     }
+#endif
 
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if (active == true)
-        {
-            range_comp_img[i] = 0;
-        }
-        else 
-        {
-            range_comp_img[i] = (max_wed - map_wed_max[i]) / (PMMA_STPR * PMMA_DENSITY);
-        }
-    }
+    cd->last_step_completed = step_num;
 
-    /* compute the max/min wed of the entire target + margins + range_comp*/
-    double total_min_wed = 0;
-    double total_max_wed = 0;
-    // Max should be the same as the max in the target as for this ray rgcomp is null
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > total_max_wed) { // if active beam line, range comp is null
-            total_max_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i];
-        }
-    }
-    total_min_wed = total_max_wed;
-    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
-    {
-        if ((range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > 0) && (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i] < total_min_wed)) {
-            total_min_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i];
-        }
+    /* GCS FIX: I have a rounding error somewhere -- maybe step_num
+       starts at 1?  Or maybe proj_vol is not big enough?  
+       This is a workaround until I can fix. */
+    if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) {
+        return;
     }
 
-    printf("Max wed in the target is %lg mm.\n", total_max_wed);
-    printf("Min wed in the target is %lg mm.\n", total_min_wed);
-
-    /* Save these values in private data store */
-    d_ptr->max_wed = total_max_wed;
-    d_ptr->min_wed = total_min_wed;
-    return;
+    depth_img[ap_area*step_num + ap_idx] = cd->accum;
 }
 
+//Added by YKPark. Relative stopping power-based water eq. path length. Valid for 20 MeV ~ 240 MeV proton beam
+//t_w = t_m * rel. density * SP ratio(m to w) = t_m*RSP
+static
 void
-Rpl_volume::compute_target_distance_limits(Volume* seg_vol, std::vector <double>& map_min_distance, std::vector <double>& map_max_distance)
+rpl_ray_trace_callback_RSP (
+    void *callback_data, 
+    size_t vox_index, 
+    double vox_len, 
+    float vox_value
+)
 {
-    double threshold = .2;  //theshold for interpolated, segmented volume
-    d_ptr->aperture->allocate_aperture_images();
-
-    Volume::Pointer aperture_vol = d_ptr->aperture->get_aperture_volume ();
-    Proj_volume *proj_vol = d_ptr->proj_vol;
-    Volume *rvol = proj_vol->get_vol();
-    float *seg_img = (float*) seg_vol->img;
-
-    //const int *ires = proj_vol->get_image_dim();  //resolution of the 2-D proj vol aperture
-    int ires2[2];  //resolution of the output - user defined aperuture and segdepth_vol
-    ires2[0] = aperture_vol->dim[0];
-    ires2[1] = aperture_vol->dim[1];
-
-    //plm_long rijk[3]; /* Index with rvol */
-    double k = 0; /* index with rvol */
-    double seg_long_ray[3] = {0, 0, 0}; // vector in the rvol volume
-    float final_index[3]; //index of final vector
-
-    //Trilinear interpoloation variables
-    plm_long ijk_floor[3];  //floor of rounded
-    plm_long ijk_round[3];  //ceiling of rounded
-    float li_1[3], li_2[3]; //upper/lower fractions
-    plm_long idx_floor;
-
-    //Interpolated seg_volume value
-    double interp_seg_value;
-
-    double previous_depth; //previous wed depth
-    bool intersect_seg; //boolean that checks whether or not ray intersects with seg. volume
-    bool first_seg_check; //first point along a ray in the seg volume, to determine min energy
-
-    Ray_data *seg_ray;
-
-    for(int i = 0; i < ires2[0] * ires2[1]; i++)
-    {
-        map_min_distance.push_back(0);
-        map_max_distance.push_back(0);
-    }
-
-    for (int i = 0; i < ires2[0] * ires2[1]; i++)
-    {
-        seg_ray = &d_ptr->ray_data[i];
-        k = 0.;
-        vec3_copy(seg_long_ray, seg_ray->cp);
-
-        /* reset variables */
-        previous_depth = 0;
-        first_seg_check = true;
-        intersect_seg = false;
-
-        while (k < (double) rvol->dim[2])
-        {
-            if (k != 0)
-            {
-                vec3_add2(seg_long_ray, seg_ray->ray);
-            }
-
-            final_index[0] = (seg_long_ray[0]-seg_vol->origin[0])/seg_vol->spacing[0];
-            final_index[1] = (seg_long_ray[1]-seg_vol->origin[1])/seg_vol->spacing[1];
-            final_index[2] = (seg_long_ray[2]-seg_vol->origin[2])/seg_vol->spacing[2];
-			
-            li_clamp_3d (final_index, ijk_floor, ijk_round,li_1,li_2,seg_vol);
-            idx_floor = volume_index(seg_vol->dim, ijk_floor);
-            interp_seg_value = li_value(li_1[0], li_2[0],li_1[1], li_2[1],li_1[2], li_2[2],idx_floor,seg_img,seg_vol);
+    Callback_data *cd = (Callback_data *) callback_data;
+    Rpl_volume *rpl_vol = cd->rpl_vol;
+    Ray_data *ray_data = cd->ray_data;
+    float *depth_img = (float*) rpl_vol->get_vol()->img;
+    int ap_idx = ray_data->ap_idx;
+    int ap_area = cd->ires[0] * cd->ires[1];
+    size_t step_num = vox_index + cd->step_offset;
 
-            if (interp_seg_value > threshold)  
-            {
-                intersect_seg = true; //this ray intersects the segmentation volume
+    cd->accum += vox_len * compute_PrSTRP_XiO_MGH_weq_from_HU (vox_value); //vox_value = CT_HU
 
-                /* If point is within segmentation volume, set distance to the map_min matrix */	  
-                if (first_seg_check)  
-                {
-                    map_min_distance[i] = k;
-                    first_seg_check = false;
-                }
-                previous_depth = k;
-            }
-            else
-            {
-                if (intersect_seg)  
-                { 
-                    /* while we aren't currently in the seg. volume, this ray has been,
-                       so check if we just exited to set the max_seg_depth */
-                    if (previous_depth > 0)
-                    {
-                        map_max_distance[i] = previous_depth;
-                        previous_depth = 0;
-                    }
-                }
-            }
-            k++;
-        }
+#if VERBOSE
+    if (global_debug) {
+	printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, 
+	    vox_value, cd->accum);
+        printf ("dim = %d %d %d\n", 
+            (int) rpl_vol->get_vol()->dim[0],
+            (int) rpl_vol->get_vol()->dim[1],
+            (int) rpl_vol->get_vol()->dim[2]);
+        printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", 
+            ap_area, (int) ap_idx, vox_len);
     }
-    return;
-}
-
-void
-Rpl_volume::compute_target_distance_limits_slicerRt(Plm_image::Pointer& plmTgt, std::vector <double>& map_min_distance, std::vector <double>& map_max_distance)
-{
-    double threshold = .2;  //theshold for interpolated, segmented volume
-    d_ptr->aperture->allocate_aperture_images();
-
-    Volume::Pointer aperture_vol = d_ptr->aperture->get_aperture_volume ();
-    Proj_volume *proj_vol = d_ptr->proj_vol;
-    Volume *rvol = proj_vol->get_vol();
-    unsigned char* seg_img = (unsigned char*) plmTgt->get_volume_uchar()->img;
-
-    //const int *ires = proj_vol->get_image_dim();  //resolution of the 2-D proj vol aperture
-    int ires2[2];  //resolution of the output - user defined aperuture and segdepth_vol
-    ires2[0] = aperture_vol->dim[0];
-    ires2[1] = aperture_vol->dim[1];
-
-    //plm_long rijk[3]; /* Index with rvol */
-    double k = 0; /* index with rvol */
-    double seg_long_ray[3] = {0, 0, 0}; // vector in the rvol volume
-    float final_index[3]; //index of final vector
-
-    //Trilinear interpoloation variables
-    plm_long ijk_floor[3];  //floor of rounded
-    plm_long ijk_round[3];  //ceiling of rounded
-    float li_1[3], li_2[3]; //upper/lower fractions
-    plm_long idx_floor;
-    double A = 0; double B = 0; double C = 0; double D = 0; double E = 0; double F = 0; double G = 0; double H = 0;
-
-    //Interpolated seg_volume value
-    double interp_seg_value;
-
-    lprintf ("tgt dim = %d,%d,%d\n", (int) plmTgt->dim(0), (int) plmTgt->dim(1), (int) plmTgt->dim(2));
-    lprintf ("tgt origin = %g,%g,%g\n", plmTgt->origin(0), plmTgt->origin(1), plmTgt->origin(2));
-    lprintf ("tgt spacing = %g,%g,%g\n", plmTgt->spacing(0), plmTgt->spacing(1), plmTgt->spacing(2));
-    fflush (stdout);
-    plm_long dim[3] = {(plm_long) plmTgt->dim(0), (plm_long) plmTgt->dim(1), (plm_long) plmTgt->dim(2)};
-
-    double previous_depth; //previous wed depth
-    bool intersect_seg; //boolean that checks whether or not ray intersects with seg. volume
-    bool first_seg_check; //first point along a ray in the seg volume, to determine min energy
+#endif
 
-    Ray_data *seg_ray;
+    cd->last_step_completed = step_num;
 
-    for(int i = 0; i < ires2[0] * ires2[1]; i++)
-    {
-        map_min_distance.push_back(0);
-        map_max_distance.push_back(0);
+    /* GCS FIX: I have a rounding error somewhere -- maybe step_num
+       starts at 1?  Or maybe proj_vol is not big enough?  
+       This is a workaround until I can fix. */
+    if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) {
+        return;
     }
 
-    for (int i = 0; i < ires2[0] * ires2[1]; i++)
-    {
-        seg_ray = &d_ptr->ray_data[i];
-        k = 0.;
-        vec3_copy(seg_long_ray, seg_ray->cp);
-
-        /* reset variables */
-        previous_depth = 0;
-        first_seg_check = true;
-        intersect_seg = false;
-
-        while (k < (double) rvol->dim[2])
-        {
-            if (k != 0)
-            {
-                vec3_add2(seg_long_ray, seg_ray->ray);
-            }
-
-            final_index[0] = (seg_long_ray[0] - plmTgt->origin(0))/plmTgt->spacing(0);
-            final_index[1] = (seg_long_ray[1] - plmTgt->origin(1))/plmTgt->spacing(1);
-            final_index[2] = (seg_long_ray[2] - plmTgt->origin(2))/plmTgt->spacing(2);
-            if (final_index[0] < 0 || final_index[0] > (float) plmTgt->dim(0) || final_index[1] < 0 || final_index[1] > (float) plmTgt->dim(1) || final_index[2] < 0 || final_index[2] > (float) plmTgt->dim(2))
-            {
-                interp_seg_value = 0;
-            }
-            else
-            {
-                /* Li_clamp_3D */
-                li_clamp (final_index[0], plmTgt->dim(0)-1, &ijk_floor[0], &ijk_round[0], &li_1[0], &li_2[0]);
-                li_clamp (final_index[1], plmTgt->dim(1)-1, &ijk_floor[1], &ijk_round[1], &li_1[1], &li_2[1]);
-                li_clamp (final_index[2], plmTgt->dim(2)-1, &ijk_floor[2], &ijk_round[2], &li_1[2], &li_2[2]);
-			
-                idx_floor = volume_index (dim, ijk_floor);
-
-                /* li_value for Volume* */
-                A = li_1[0] * li_1[1] * li_1[2] * (double)seg_img[idx_floor];
-                B = li_2[0] * li_1[1] * li_1[2] * (double)seg_img[idx_floor+1];
-                C = li_1[0] * li_2[1] * li_1[2] * (double)seg_img[idx_floor+dim[0] ];
-                D = li_2[0] * li_2[1] * li_1[2] * (double)seg_img[idx_floor+dim[0]+1];
-                E = li_1[0] * li_1[1] * li_2[2] * (double)seg_img[idx_floor+dim[1]*dim[0] ];
-                F = li_2[0] * li_1[1] * li_2[2] * (double)seg_img[idx_floor+dim[1]*dim[0]+1];
-                G = li_1[0] * li_2[1] * li_2[2] * (double)seg_img[idx_floor+dim[1]*dim[0]+dim[0] ];
-                H = li_2[0] * li_2[1] * li_2[2] * (double)seg_img[idx_floor+dim[1]*dim[0]+dim[0]+1];
-                interp_seg_value = A + B + C + D + E + F + F + G + H;
-            }
-
-            if (interp_seg_value > threshold)  
-            {
-                intersect_seg = true; //this ray intersects the segmentation volume
-
-                /* If point is within segmentation volume, set distance to the map_min matrix */	  
-                if (first_seg_check)  
-                {
-                    map_min_distance[i] = k;
-                    first_seg_check = false;
-                }
-                previous_depth = k;
-            }
-            else
-            {
-                if (intersect_seg)  
-                { 
-                    /* while we aren't currently in the seg. volume, this ray has been,
-                       so check if we just exited to set the max_seg_depth */
-                    if (previous_depth > 0)
-                    {
-                        map_max_distance[i] = previous_depth;
-                        previous_depth = 0;
-                    }
-                }
-            }
-            k++;
-        }
-    }
-    return;
+    depth_img[ap_area*step_num + ap_idx] = cd->accum;
 }
 
-//20140827_YKP
-//col0 = HU, col1 = Relative stopping power
-//Table: XiO, ctedproton 2007 provided by Yoost
-extern const double lookup_PrSTPR_XiO_MGH[][2] ={
-    -1000.0,    0.01,
-    0.0,        1.0,
-    40.0,       1.04,
-    1000.0,     1.52,
-    2000.0,     2.02,
-    3000.0,     2.55,
-};
diff --git a/src/plastimatch/base/rpl_volume.h b/src/plastimatch/base/rpl_volume.h
old mode 100644
new mode 100755
index 02f1423..96701fa
--- a/src/plastimatch/base/rpl_volume.h
+++ b/src/plastimatch/base/rpl_volume.h
@@ -16,11 +16,7 @@
 
 PLMBASE_API float compute_PrSTPR_from_HU(float);
 PLMBASE_API float compute_PrSTPR_Schneider_weq_from_HU (float CT_HU); // Stopping Power Ratio - Schneider's model
-PLMBASE_API float compute_PrSTRP_XiO_MGH_weq_from_HU (float CT_HU); // Stopping power Ratio - XiO values from MGH
 PLMBASE_API float compute_PrWER_from_HU(float CT_HU); // WER = STRP / density
-
-extern const double lookup_PrSTPR_XiO_MGH[][2];
-
 PLMBASE_API float compute_density_from_HU (float CT_HU); // density VS HU - Schneider's model: broken curve
 
 class Proj_volume;
@@ -29,6 +25,11 @@ class Rpl_volume_private;
 class Volume;
 class Volume_limit;
 
+enum Rpl_volume_ray_trace_start {
+    RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION,
+    RAY_TRACE_START_AT_CLIPPING_PLANE
+};
+
 class PLMBASE_API Rpl_volume 
 {
 public:
@@ -43,13 +44,14 @@ public:
         const double iso[3],           // position of isocenter (mm)
         const double vup[3],           // dir to "top" of projection plane
         double sid,                    // dist from proj plane to source (mm)
-        const int image_dim[2],        // resolution of image
+        const plm_long image_dim[2],   // resolution of image
         const double image_center[2],  // image center (pixels)
         const double image_spacing[2], // pixel size (mm)
         const double step_length       // spacing between planes
     );
+    void clone_geometry (const Rpl_volume *rv);
 
-    void set_ct_volume (Plm_image::Pointer& ct_volume);
+    void set_ray_trace_start (Rpl_volume_ray_trace_start rvrtt);
 
     Aperture::Pointer& get_aperture ();
     const Aperture::Pointer& get_aperture () const;
@@ -58,31 +60,41 @@ public:
     Volume* get_vol ();
     const Volume* get_vol () const;
     Proj_volume* get_proj_volume ();
+    void set_ct_volume (Plm_image::Pointer& ct_volume);
+
+    const Proj_volume* get_proj_volume () const;
+
+    const plm_long *get_image_dim ();
+    plm_long get_num_steps ();
 
-    double get_rgdepth (int ap_ij[2], double dist);
-    double get_rgdepth (double ap_ij[2], double dist);
-    double get_rgdepth (const double *xyz);
+    double get_value (plm_long ap_ij[2], double dist) const;
+    double get_value (double ap_ij[2], double dist) const;
+    double get_value (const double *xyz) const;
 
     void set_ct (const Plm_image::Pointer& ct_volume);
     Plm_image::Pointer get_ct();
+
     void set_ct_limit(Volume_limit* ct_limit);
     Volume_limit* get_ct_limit();
-    void set_ray(Ray_data *ray);
-    Ray_data* get_Ray_data();
+
+    Ray_data* get_ray_data();
+    const Ray_data* get_ray_data() const;
+    void set_ray_data (Ray_data *ray);
+
     void set_front_clipping_plane(double front_clip);
     double get_front_clipping_plane () const;
     void set_back_clipping_plane(double back_clip);
     double get_back_clipping_plane () const;
-    void set_minimum_distance_target(double min);
-    double get_minimum_distance_target();
-
-    double get_max_wed ();
-    double get_min_wed ();
+    double get_step_length () const;
 
     void compute_rpl_ct_density (); // compute density volume
     void compute_rpl_HU ();	// compute HU volume
     void compute_rpl_void ();	// compute void volume
 
+    void compute_rpl (bool use_aperture, Ray_trace_callback callback);
+    void compute_rpl_sample (bool use_aperture);
+    void compute_rpl_accum (bool use_aperture);
+    
     void compute_rpl_range_length_rgc(); // range length volume creation taking into account the range compensator
     void compute_rpl_PrSTRP_no_rgc (); // compute Proton Stopping Power Ratio volume without considering the range compensator
 
@@ -92,14 +104,6 @@ public:
     void compute_dew_volume (Volume *wed_vol, Volume *dew_vol, float background);
     void compute_proj_wed_volume (Volume *proj_wed_vol, float background);
     
-    void compute_beam_modifiers_passive_scattering (Volume *seg_vol);
-    void compute_beam_modifiers_active_scanning (Volume *seg_vol);
-    void compute_beam_modifiers_passive_scattering (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin);
-    void compute_beam_modifiers_passive_scattering_slicerRt(Plm_image::Pointer& plmTgt, float smearing, float proximal_margin, float distal_margin);
-    void compute_beam_modifiers_active_scanning (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin);
-    void compute_beam_modifiers_passive_scattering (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max); // returns also the wed max and min maps
-    void compute_beam_modifiers_active_scanning (Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max); // returns also the wed max and min maps
-
     void compute_volume_aperture(Aperture::Pointer ap);
 
     void apply_beam_modifiers ();
@@ -112,14 +116,8 @@ public:
     void load_img (const std::string& filename);
 
     void compute_ray_data ();
-    void compute_beam_modifiers_core_slicerRt (Plm_image::Pointer& plmTgt, bool active, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max);
 
 protected:
-    void compute_beam_modifiers_core (Volume *seg_vol, bool active, float smearing, float proximal_margin, float distal_margin, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max);
-    void compute_target_distance_limits (Volume* seg_vol, std::vector <double>& map_min_distance, std::vector <double>& map_max_distance);
-    void compute_target_distance_limits_slicerRt (Plm_image::Pointer& plmTgt, std::vector <double>& map_min_distance, std::vector <double>& map_max_distance);
-    void apply_smearing_to_target (float smearing, std::vector <double>& map_min_distance, std::vector <double>& map_max_distance);
-
     void rpl_ray_trace (
         Volume *ct_vol,              /* I: CT volume */
         Ray_data *ray_data,          /* I: Pre-computed data for this ray */
diff --git a/src/plastimatch/base/rpl_volume_lut.cxx b/src/plastimatch/base/rpl_volume_lut.cxx
new file mode 100755
index 0000000..3258843
--- /dev/null
+++ b/src/plastimatch/base/rpl_volume_lut.cxx
@@ -0,0 +1,163 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmbase_config.h"
+
+#include "interpolate.h"
+#include "proj_volume.h"
+#include "ray_data.h"
+#include "rpl_volume.h"
+#include "rpl_volume_lut.h"
+#include "volume.h"
+
+class Lut_entry
+{
+public:
+    Lut_entry() {
+        for (int i = 0; i < 8; i++) {
+            idx[i] = -i;
+            weight[i] = 0.f;
+        }
+    }
+public:
+    plm_long idx[8];
+    float weight[8];
+};
+
+class PLMBASE_API Rpl_volume_lut_private
+{
+public:
+    Rpl_volume_lut_private (Rpl_volume *rv, Volume *vol)
+        : rv(rv), vol(vol), lut(0)
+    {
+    }
+    ~Rpl_volume_lut_private ()
+    {
+        delete[] lut;
+    }
+public:
+    Rpl_volume *rv;
+    Volume *vol;
+    Lut_entry *lut;
+};
+
+Rpl_volume_lut::Rpl_volume_lut ()
+{
+    d_ptr = new Rpl_volume_lut_private (0, 0);
+}
+
+Rpl_volume_lut::Rpl_volume_lut (Rpl_volume *rv, Volume *vol)
+{
+    d_ptr = new Rpl_volume_lut_private (rv, vol);
+}
+
+Rpl_volume_lut::~Rpl_volume_lut ()
+{
+    delete d_ptr;
+}
+
+void 
+Rpl_volume_lut::set_lut_entry (
+    const Ray_data* ray_data, 
+    plm_long vox_idx, 
+    const float *vox_ray, 
+    plm_long ap_idx, 
+    float li_frac, 
+    float step_length, 
+    int lut_entry_idx
+)
+{
+    // Make sure this ray has positive weight
+    if (li_frac <= 0.f) {
+        return;
+    }
+
+    // Project voxel vector onto unit vector of aperture ray
+    // This assumes that 
+    // d_ptr->rvrts == RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION
+    // We omit the check for speed.
+    const double *ap_ray = ray_data[ap_idx].ray;
+    float dist = vec3_dot (vox_ray, ap_ray);
+    dist -= ray_data->front_dist;
+    if (dist < 0) {
+        return;
+    }
+
+    // Compute number of steps
+    plm_long steps_f = (plm_long) floorf (dist / step_length);
+    float dist_frac = (dist - steps_f * step_length) / step_length;
+    if (steps_f >= d_ptr->rv->get_num_steps()) {
+        return;
+    }
+    
+    // Compute lut entries
+    const Aperture::Pointer ap = d_ptr->rv->get_aperture ();
+    plm_long lut_idx = ap_idx + steps_f * ap->get_dim(0) * ap->get_dim(1);
+    d_ptr->lut[lut_idx].idx[lut_entry_idx] = lut_idx;
+    d_ptr->lut[lut_idx].weight[lut_entry_idx] = dist_frac * li_frac;
+
+    if (steps_f >= d_ptr->rv->get_num_steps() - 1) {
+        return;
+    }
+    lut_idx = lut_idx + ap->get_dim(0) * ap->get_dim(1);
+    d_ptr->lut[lut_idx].idx[4+lut_entry_idx] = lut_idx;
+    d_ptr->lut[lut_idx].weight[4+lut_entry_idx] = (1. - dist_frac) * li_frac;
+}
+
+void 
+Rpl_volume_lut::build_lut ()
+{
+    const Proj_volume *pv = d_ptr->rv->get_proj_volume ();
+    const double *src = pv->get_src ();
+    const Aperture::Pointer ap = d_ptr->rv->get_aperture ();
+    const plm_long *ap_dim = ap->get_dim ();
+    const Ray_data* ray_data = d_ptr->rv->get_ray_data();
+
+    /* Allocate memory for lut */
+    d_ptr->lut = new Lut_entry[d_ptr->vol->npix];
+
+    plm_long ijk[3];
+    double xyz[3];
+    LOOP_Z (ijk, xyz, d_ptr->vol) {
+        LOOP_Y (ijk, xyz, d_ptr->vol) {
+            LOOP_X (ijk, xyz, d_ptr->vol) {
+                plm_long idx = d_ptr->vol->index (ijk);
+
+                /* Project the voxel to the aperture plane */
+                double ap_xy[2];
+                pv->project (ap_xy, xyz);
+                if (!is_number (ap_xy[0]) || !is_number (ap_xy[1])) {
+                    continue;
+                }
+
+                /* Check if voxel is completely outside aperture boundary */
+                if (ap_xy[0] <= -1.f || ap_xy[0] >= ap_dim[0]
+                    || ap_xy[1] <= -1.f || ap_xy[1] >= ap_dim[1])
+                {
+                    continue;
+                }
+                
+                /* Get vector from source to voxel */
+                float vox_ray[3];
+                vec3_sub3 (vox_ray, xyz, src);
+
+                /* Solve for interpolation fractions on aperture planes */
+                plm_long ijk_f[3];
+                float li_frac_1[3], li_frac_2[3];
+                float ap_xy_float[2] = { ap_xy[0], ap_xy[1] };
+                li_2d (ijk_f, li_frac_1, li_frac_2, ap_xy_float, ap_dim);
+
+                /* Inspect four interpolant aperture pixels.  
+                   For each pixel, calculate distance to point 
+                   on ray closest to voxel center */
+                plm_long ap_ij[2], ap_idx;
+                ap_ij[0] = ijk_f[0], ap_ij[1] = ijk_f[1];
+                ap_idx = ap_ij[0] + ap_ij[1] * ap_dim[0];
+
+                set_lut_entry (ray_data, idx, vox_ray, 
+                    ap_idx, li_frac_1[0], li_frac_2[0], 0);
+                
+            }
+        }
+    }
+}
diff --git a/src/plastimatch/base/rpl_volume_lut.h b/src/plastimatch/base/rpl_volume_lut.h
new file mode 100755
index 0000000..fcc8087
--- /dev/null
+++ b/src/plastimatch/base/rpl_volume_lut.h
@@ -0,0 +1,37 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _rpl_volume_lut_h_
+#define _rpl_volume_lut_h_
+
+#include "plmbase_config.h"
+#include "smart_pointer.h"
+
+class Rpl_volume;
+class Rpl_volume_lut_private;
+class Volume;
+
+class PLMBASE_API Rpl_volume_lut 
+{
+public:
+    SMART_POINTER_SUPPORT (Rpl_volume_lut);
+    Rpl_volume_lut_private *d_ptr;
+public:
+    Rpl_volume_lut ();
+    Rpl_volume_lut (Rpl_volume *rv, Volume *vol);
+    ~Rpl_volume_lut ();
+public:
+    void build_lut ();
+protected:
+    void set_lut_entry (
+        const Ray_data* ray_data, 
+        plm_long vox_idx, 
+        const float *vox_ray, 
+        plm_long ap_idx, 
+        float li_frac, 
+        float step_length, 
+        int lut_entry_idx
+    );
+};
+
+#endif
diff --git a/src/plastimatch/base/rt_study_metadata.cxx b/src/plastimatch/base/rt_study_metadata.cxx
old mode 100755
new mode 100644
index ce41c13..093b959
--- a/src/plastimatch/base/rt_study_metadata.cxx
+++ b/src/plastimatch/base/rt_study_metadata.cxx
@@ -15,12 +15,17 @@
 class Rt_study_metadata_private {
 public:
     std::string date_string;
+    std::string description_string;
+    std::string referring_physician_name_string;
+    std::string accession_number_string;
     std::string time_string;
     std::string study_id_string;
 
     std::string study_uid;
     std::string for_uid;
 
+    std::string position_reference_indicator_string;
+
     std::string ct_series_uid;
     std::string dose_instance_uid;
     std::string dose_series_uid;
@@ -112,9 +117,15 @@ Rt_study_metadata::set_ct_series_uid (const char* uid)
 }
 
 const char*
+Rt_study_metadata::get_ct_series_description () const
+{
+    return this->get_image_metadata (0x0008, 0x103E).c_str();
+}
+
+const std::string&
 Rt_study_metadata::get_dose_instance_uid () const
 {
-    return d_ptr->dose_instance_uid.c_str();
+    return d_ptr->dose_instance_uid;
 }
 
 const char*
@@ -142,10 +153,17 @@ Rt_study_metadata::get_plan_instance_uid () const
     return d_ptr->plan_instance_uid.c_str();
 }
 
-const char*
+const std::string&
 Rt_study_metadata::get_rtstruct_instance_uid () const
 {
-    return d_ptr->rtstruct_instance_uid.c_str();
+    return d_ptr->rtstruct_instance_uid;
+}
+
+void
+Rt_study_metadata::set_rtstruct_instance_uid (const char* rtstruct_instance_uid)
+{
+    if (!rtstruct_instance_uid) return;
+    d_ptr->rtstruct_instance_uid = rtstruct_instance_uid;
 }
 
 const char*
@@ -155,6 +173,82 @@ Rt_study_metadata::get_rtstruct_series_uid () const
 }
 
 const char*
+Rt_study_metadata::get_referring_physician_name () const
+{
+    return d_ptr->referring_physician_name_string.c_str();
+}
+
+void
+Rt_study_metadata::set_referring_physician_name (const char* referring_physician_name)
+{
+    if (!referring_physician_name) return;
+    d_ptr->referring_physician_name_string = referring_physician_name;
+}
+
+void
+Rt_study_metadata::set_referring_physician_name (const std::string& referring_physician_name)
+{
+    d_ptr->referring_physician_name_string = referring_physician_name;
+}
+
+const char*
+Rt_study_metadata::get_position_reference_indicator () const
+{
+    return d_ptr->position_reference_indicator_string.c_str();
+}
+
+void
+Rt_study_metadata::set_position_reference_indicator (const char* position_reference_indicator)
+{
+    if (!position_reference_indicator) return;
+    d_ptr->position_reference_indicator_string = position_reference_indicator;
+}
+
+void
+Rt_study_metadata::set_position_reference_indicator (const std::string& position_reference_indicator)
+{
+    d_ptr->position_reference_indicator_string = position_reference_indicator;
+}
+
+const char*
+Rt_study_metadata::get_accession_number () const
+{
+    return d_ptr->accession_number_string.c_str();
+}
+
+void
+Rt_study_metadata::set_accession_number (const char* accession_number)
+{
+    if (!accession_number) return;
+    d_ptr->accession_number_string = accession_number;
+}
+
+void
+Rt_study_metadata::set_accession_number (const std::string& accession_number)
+{
+    d_ptr->accession_number_string = accession_number;
+}
+
+const char*
+Rt_study_metadata::get_study_description () const
+{
+    return d_ptr->description_string.c_str();
+}
+
+void
+Rt_study_metadata::set_study_description (const char* description)
+{
+    if (!description) return;
+    d_ptr->description_string = description;
+}
+
+void
+Rt_study_metadata::set_study_description (const std::string& description)
+{
+    d_ptr->description_string = description;
+}
+
+const char*
 Rt_study_metadata::get_study_date () const
 {
     return d_ptr->date_string.c_str();
@@ -182,8 +276,10 @@ Rt_study_metadata::get_study_time () const
 void
 Rt_study_metadata::set_study_time (const char* time)
 {
-    if (!time) return;
-    d_ptr->time_string = time;
+    if (!time)
+      d_ptr->time_string.clear();
+    else 
+      d_ptr->time_string = time;
 }
 
 void
@@ -404,7 +500,8 @@ const std::string&
 Rt_study_metadata::get_image_metadata (
     unsigned short key1, 
     unsigned short key2
-) {
+) const
+{
     return d_ptr->image_metadata->get_metadata (key1, key2);
 }
 
diff --git a/src/plastimatch/base/rt_study_metadata.h b/src/plastimatch/base/rt_study_metadata.h
old mode 100755
new mode 100644
index 0efd8ab..77e0615
--- a/src/plastimatch/base/rt_study_metadata.h
+++ b/src/plastimatch/base/rt_study_metadata.h
@@ -38,18 +38,36 @@ public:
 public:
     const char* get_ct_series_uid () const;
     void set_ct_series_uid (const char* uid);
-    const char* get_dose_instance_uid () const;
+    const char* get_ct_series_description () const;
+    const std::string& get_dose_instance_uid () const;
     const char* get_dose_series_uid () const;
     const char* get_frame_of_reference_uid () const;
     void set_frame_of_reference_uid (const char* uid);
     const char* get_plan_instance_uid () const;
-    const char* get_rtstruct_instance_uid () const;
+    const std::string& get_rtstruct_instance_uid () const;
+    void set_rtstruct_instance_uid (const char* rtstruct_instance_uid);
     const char* get_rtstruct_series_uid () const;
 
+    const char* get_position_reference_indicator () const;
+    void set_position_reference_indicator (const char* position_reference_indicator);
+    void set_position_reference_indicator (const std::string& position_reference_indicator);
+
+    const char* get_referring_physician_name () const;
+    void set_referring_physician_name (const char* referring_physician_name);
+    void set_referring_physician_name (const std::string& referring_physician_name);
+
+    const char* get_accession_number () const;
+    void set_accession_number (const char* accession_number);
+    void set_accession_number (const std::string& accession_number);
+
     const char* get_study_date () const;
     void set_study_date (const char* date);
     void set_study_date (const std::string& date);
 
+    const char* get_study_description () const;
+    void set_study_description (const char* description);
+    void set_study_description (const std::string& description);
+
     const char* get_study_time () const;
     void set_study_time (const char* time);
     void set_study_time (const std::string& time);
@@ -98,7 +116,7 @@ public:
     Metadata::Pointer& get_image_metadata ();
     const Metadata::Pointer& get_image_metadata () const;
     const std::string& get_image_metadata (unsigned short key1, 
-        unsigned short key2);
+        unsigned short key2) const;
     void set_image_metadata (unsigned short key1, unsigned short key2,
         const std::string& val);
     Metadata::Pointer& get_rtstruct_metadata ();
diff --git a/src/plastimatch/base/rt_study_p.h b/src/plastimatch/base/rt_study_p.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/rtplan.cxx b/src/plastimatch/base/rtplan.cxx
index bc90eca..096c2ca 100644
--- a/src/plastimatch/base/rtplan.cxx
+++ b/src/plastimatch/base/rtplan.cxx
@@ -37,6 +37,7 @@ void
 Rtplan::clear(void)
 {
     this->number_of_fractions_planned = 0;
+    this->patient_position = "HFS";
     this->snout_id = "";
     this->general_accessory_id = "";
     this->general_accessory_code = "";
@@ -44,12 +45,22 @@ Rtplan::clear(void)
     this->range_shifter_code = "";
     this->range_modulator_id = "";
     this->range_modulator_code = "";
+    this->rt_plan_label = "";
+    this->rt_plan_name = "";
+    this->rt_plan_date = "";
+    this->rt_plan_time = "";
+    this->fraction_group_description = "";
+    this->number_of_fraction_pattern_digits_per_day = "";
+    this->repeat_fraction_cycle_length = "";
+    this->fraction_pattern = "";
     this->tolerance_table_label = "";
     this->tolerance_gantry_angle = "";
     this->tolerance_patient_support_angle = "";
     this->tolerance_table_top_vertical = "";
     this->tolerance_table_top_longitudinal = "";
     this->tolerance_table_top_lateral = "";
+    this->tolerance_table_top_pitch = "";
+    this->tolerance_table_top_roll = "";
     this->tolerance_snout_position = "";
     for (size_t i = 0; i < this->beamlist.size(); i++) {
         delete this->beamlist[i];
diff --git a/src/plastimatch/base/rtplan.h b/src/plastimatch/base/rtplan.h
index ecf87ff..75bed18 100644
--- a/src/plastimatch/base/rtplan.h
+++ b/src/plastimatch/base/rtplan.h
@@ -22,19 +22,35 @@ public:
     SMART_POINTER_SUPPORT(Rtplan);
 public:
     size_t number_of_fractions_planned;
+    std::string patient_position;
     std::string snout_id;
     std::string general_accessory_id;
     std::string general_accessory_code;
+    std::string number_of_range_shifters;
     std::string range_shifter_id;
+    std::string range_shifter_number;
     std::string range_shifter_code;
+    std::string range_shifter_type;
     std::string range_modulator_id;
     std::string range_modulator_code;
+    std::string patient_support_id;    
+    std::string patient_support_accessory_code;
+    std::string rt_plan_label;
+    std::string rt_plan_name;
+    std::string rt_plan_date;
+    std::string rt_plan_time;
+    std::string fraction_group_description;
+    std::string number_of_fraction_pattern_digits_per_day;
+    std::string repeat_fraction_cycle_length;
+    std::string fraction_pattern;
     std::string tolerance_table_label;
     std::string tolerance_gantry_angle;
     std::string tolerance_patient_support_angle;
     std::string tolerance_table_top_vertical;
     std::string tolerance_table_top_longitudinal;
     std::string tolerance_table_top_lateral;
+    std::string tolerance_table_top_pitch;
+    std::string tolerance_table_top_roll;
     std::string tolerance_snout_position;
     std::vector<Rtplan_beam*> beamlist;
 public:
diff --git a/src/plastimatch/base/rtplan_beam.cxx b/src/plastimatch/base/rtplan_beam.cxx
index ce143c4..621317e 100644
--- a/src/plastimatch/base/rtplan_beam.cxx
+++ b/src/plastimatch/base/rtplan_beam.cxx
@@ -27,8 +27,28 @@ Rtplan_beam::clear()
 {  
     this->name = "";
     this->description = "";
+    this->treatment_machine_name = "";
+    this->treatment_delivery_type = "";
     this->final_cumulative_meterset_weight = 0.f;
     this->snout_position = 0.f;
+    this->gantry_angle = 0.f;
+    this->gantry_rotation_direction = "NONE";
+    this->beam_limiting_device_angle = 0.f;
+    this->beam_limiting_device_rotation_direction = "NONE";
+    this->patient_support_angle = 0.f;
+    this->patient_support_rotation_direction = "NONE";
+    this->table_top_vertical_position = 0.f;
+    this->table_top_longitudinal_position = 0.f;
+    this->table_top_lateral_position = 0.f;
+    this->table_top_pitch_angle = 0.f;
+    this->table_top_pitch_rotation_direction = "NONE";
+    this->table_top_roll_angle = 0.f;
+    this->table_top_roll_rotation_direction = "NONE";
+    this->gantry_pitch_angle = 0.f;
+    this->gantry_pitch_rotation_direction = "NONE";
+    this->isocenter_position[0] = 0.f;
+    this->isocenter_position[1] = 0.f;
+    this->isocenter_position[2] = 0.f;
 
     for (size_t i = 0; i < this->cplist.size(); i++) {
         delete this->cplist[i];
@@ -44,29 +64,6 @@ Rtplan_beam::add_control_pt ()
     return new_control_pt;
 }
 
-/* first beam isocenter position*/
-#if defined (commentout)
-float*
-Rtplan_beam::get_isocenter_pos()
-{
-    float isopos[3];
-
-    isopos[0] = 0.0;
-    isopos[1] = 0.0;
-    isopos[2] = 0.0;
-
-    if (num_cp < 1)
-        return isopos;
-
-    /* Get First CP's isocenter position*/
-    isopos[0] = cplist[0]->iso_pos[0];
-    isopos[1] = cplist[0]->iso_pos[1];
-    isopos[2] = cplist[0]->iso_pos[2];
-
-    return isopos;
-}
-#endif
-
 bool 
 Rtplan_beam::check_isocenter_identical()
 {
diff --git a/src/plastimatch/base/rtplan_beam.h b/src/plastimatch/base/rtplan_beam.h
index 0b8e548..04c7ae7 100644
--- a/src/plastimatch/base/rtplan_beam.h
+++ b/src/plastimatch/base/rtplan_beam.h
@@ -18,6 +18,16 @@ public:
     std::string name;    
     /*! \brief Beam description */
     std::string description;
+    /*! \other brief descriptions */
+    std::string treatment_machine_name;
+    std::string treatment_delivery_type;
+    std::string manufacturer;
+    std::string institution_name;
+    std::string institution_address;
+    std::string institutional_department_name;
+    std::string manufacturer_model_name;
+    std::string virtual_source_axis_distances;
+
     /*! \brief Meterset at end of all control points */
     float final_cumulative_meterset_weight;
     /*! \brief Coordiates of point where beam dose is specified */
@@ -25,10 +35,27 @@ public:
     /*! \brief Dose in Gy at beam specification point */
     float beam_dose;
     float snout_position;
+    float gantry_angle;
+    std::string gantry_rotation_direction;
+    float beam_limiting_device_angle;
+    std::string beam_limiting_device_rotation_direction;
+    float patient_support_angle;
+    std::string patient_support_rotation_direction;
+    float table_top_vertical_position;
+    float table_top_longitudinal_position;
+    float table_top_lateral_position;
+    float table_top_pitch_angle;
+    std::string table_top_pitch_rotation_direction;
+    float table_top_roll_angle;
+    std::string table_top_roll_rotation_direction;
+    float gantry_pitch_angle;
+    std::string gantry_pitch_rotation_direction;
+    float isocenter_position[3];
 
     /*! \brief Control point list */
     std::vector<Rtplan_control_pt*> cplist;
 
+
 public:
     Rtplan_beam();
     ~Rtplan_beam();
@@ -36,9 +63,6 @@ public:
     void clear ();
     Rtplan_control_pt* add_control_pt ();
     bool check_isocenter_identical ();
-#if defined (commentout)
-    float* get_isocenter_pos (); //float[3], dicom coordinate
-#endif
 };
 
 
diff --git a/src/plastimatch/base/rtplan_control_pt.h b/src/plastimatch/base/rtplan_control_pt.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/rtss.cxx b/src/plastimatch/base/rtss.cxx
index d7b846e..a82b61e 100644
--- a/src/plastimatch/base/rtss.cxx
+++ b/src/plastimatch/base/rtss.cxx
@@ -558,7 +558,7 @@ void
 Rtss::keyholize (void)
 {
     /* Loop through structures */
-    for (int i = 0; i < this->num_structures; i++) {
+    for (size_t i = 0; i < this->num_structures; i++) {
         lprintf ("Keyholizing structure %d.\n", i);
 	Rtss_roi *curr_structure = this->slist[i];
 
@@ -567,7 +567,7 @@ Rtss::keyholize (void)
 	std::vector<bool> used_contours;
 	used_contours.assign (curr_structure->num_contours, false);
 
-	for (int j = 0; j < curr_structure->num_contours; j++) {
+	for (size_t j = 0; j < curr_structure->num_contours; j++) {
 	    std::vector<int> group_contours;
 	    Rtss_contour *group_polyline = curr_structure->pslist[j];
 	    if (group_polyline->num_vertices == 0) {
@@ -579,7 +579,7 @@ Rtss::keyholize (void)
 	    }
 	    float group_z = group_polyline->z[0];
 	    group_contours.push_back (j);
-	    for (int k = j+1; k < curr_structure->num_contours; k++) {
+	    for (size_t k = j+1; k < curr_structure->num_contours; k++) {
 		Rtss_contour *curr_polyline = curr_structure->pslist[k];
 		if (curr_polyline->num_vertices == 0) {
 		    curr_polyline->slice_no = -1;
@@ -593,11 +593,13 @@ Rtss::keyholize (void)
 	    }
 
 	    /* We have now found a group */
+#if defined (commentout)
 	    lprintf ("Keyholizing group:");
 	    for (size_t k = 0; k < group_contours.size(); k++) {
 		lprintf (" %d", group_contours[k]);
 	    }
 	    lprintf ("\n");
+#endif
 
 	    /* Find xmin for each contour in group */
 	    std::vector<float> group_xmin;
@@ -605,7 +607,7 @@ Rtss::keyholize (void)
             for (size_t k = 0; k < group_contours.size(); k++) {
 		int cidx = group_contours[k];
 		Rtss_contour *curr_polyline = curr_structure->pslist[cidx];
-		for (int l = 0; l < curr_polyline->num_vertices; l++) {
+		for (size_t l = 0; l < curr_polyline->num_vertices; l++) {
 		    if (curr_polyline->x[l] < group_xmin[k]) {
                         group_xmin[k] = curr_polyline->x[l];
 		    }
@@ -620,7 +622,7 @@ Rtss::keyholize (void)
 		Rtss_contour *curr_polyline = curr_structure->pslist[cidx];
 
 		float curr_xmin = FLT_MAX;
-		for (int l = 0; l < curr_polyline->num_vertices; l++) {
+		for (size_t l = 0; l < curr_polyline->num_vertices; l++) {
 		    if (curr_polyline->x[l] < curr_xmin) {
 			curr_xmin = curr_polyline->x[l];
 		    }
@@ -635,7 +637,9 @@ Rtss::keyholize (void)
 #if defined (commentout)
             Rtss_contour *outer_polyline = curr_structure->pslist[
 #endif
+#if defined (commentout)
 	    lprintf ("Outermost contour %d, x=%f\n", cidx_xmin, xmin);
+#endif
 
 	    /* Loop through other contours, find contours contained 
 	       in this contour */
@@ -651,7 +655,7 @@ Rtss::keyholize (void)
                 if (contour_in_contour (curr_polyline, ...)
 #endif
                     
-		for (int l = 0; l < curr_polyline->num_vertices; l++) {
+		for (size_t l = 0; l < curr_polyline->num_vertices; l++) {
                     float x = curr_polyline->x[0];
                     float y = curr_polyline->y[0];
                     
diff --git a/src/plastimatch/base/slice_list.cxx b/src/plastimatch/base/slice_list.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/slice_list.h b/src/plastimatch/base/slice_list.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/thumbnail.cxx b/src/plastimatch/base/thumbnail.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/thumbnail.h b/src/plastimatch/base/thumbnail.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/vf.cxx b/src/plastimatch/base/vf.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/vf_convolve.cxx b/src/plastimatch/base/vf_convolve.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume.cxx b/src/plastimatch/base/volume.cxx
index 2076076..1502f85 100755
--- a/src/plastimatch/base/volume.cxx
+++ b/src/plastimatch/base/volume.cxx
@@ -774,7 +774,7 @@ Volume::clone (Volume_pixel_type new_type) const
 #endif
 
 float
-Volume::get_ijk_value (const float ijk[3])
+Volume::get_ijk_value (const float ijk[3]) const
 {
     plm_long ijk_f[3];
     plm_long ijk_r[3];
diff --git a/src/plastimatch/base/volume.h b/src/plastimatch/base/volume.h
index 91eff55..c53d67b 100755
--- a/src/plastimatch/base/volume.h
+++ b/src/plastimatch/base/volume.h
@@ -80,17 +80,13 @@ public:
     ~Volume ();
 public:
     /*! \brief Return a linear index to a voxel */
-    plm_long index (plm_long i, plm_long j, plm_long k) {
+    plm_long index (plm_long i, plm_long j, plm_long k) const {
         return volume_index (this->dim, i, j, k);
     }
     /*! \brief Return a linear index to a voxel */
-    plm_long index (plm_long ijk[3]) {
+    plm_long index (plm_long ijk[3]) const {
         return volume_index (this->dim, ijk);
     }
-    /*! \brief Return a world coordinates of a voxel */
-    void position (float xyz[3], const plm_long ijk[3]) {
-        POSITION_FROM_COORDS (xyz, ijk, this->origin, this->step);
-    }
     /*! \brief Initialize and allocate memory for the image */
     void create (
         const plm_long new_dim[3], 
@@ -132,6 +128,10 @@ public:
       of the center of the first voxel in the volume.
     */
     void set_origin (const float origin[3]);
+    /*! \brief Get a pointer to the volume dimensions */
+    const plm_long *get_dim (void) {
+        return dim;
+    }
     /*! \brief Get a pointer to the direction cosines.  
       Direction cosines hold the orientation of a volume. 
       They are defined as the unit length direction vectors 
@@ -175,10 +175,20 @@ public:
     */
     const float* get_proj (void) const;
 
+    /*! \brief Return a world coordinates of a voxel */
+    void position (float xyz[3], const plm_long ijk[3]) {
+        POSITION_FROM_COORDS (xyz, ijk, this->origin, this->step);
+    }
+
+    /*! \brief Return coordinates from index */
+    void coordinates (plm_long ijk[3], plm_long idx) {
+        COORDS_FROM_INDEX(ijk, idx, this->dim);
+    }
+
     /*! \brief Get the value at a voxel coordinate, clamped and 
       tri-linearly interpolated.  Only applies to float volumes.
     */
-    float get_ijk_value (const float xyz[3]);
+    float get_ijk_value (const float xyz[3]) const;
     void get_xyz_from_ijk (double xyz[3], const int ijk[3]);
 
     void get_ijk_from_xyz (int ijk[3], const float xyz[3], bool* in);
diff --git a/src/plastimatch/base/volume_boundary_behavior.h b/src/plastimatch/base/volume_boundary_behavior.h
new file mode 100644
index 0000000..0831bf5
--- /dev/null
+++ b/src/plastimatch/base/volume_boundary_behavior.h
@@ -0,0 +1,24 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _volume_boundary_behavior_h_
+#define _volume_boundary_behavior_h_
+
+#include "plmbase_config.h"
+
+/*! \brief This enum is used to control the algorithm behavior 
+  for voxels at the edge of the volume.  If ZERO_PADDING is 
+  specified, all non-zero voxels at the edge of the volume 
+  will be treated as boundary voxels.  If EDGE_PADDING is 
+  specified, non-zero voxels at the edge of the volume are 
+  only treated as boundary voxels if they neighbor 
+  a zero voxel.  If ADAPTIVE_PADDING, it will use 
+  EDGE_PADDING for dimensions of a single voxel, and ZERO_PADDING 
+  for dimensions of multiple voxels. */
+enum Volume_boundary_behavior {
+    ZERO_PADDING,
+    EDGE_PADDING,
+    ADAPTIVE_PADDING
+};
+
+#endif
diff --git a/src/plastimatch/base/volume_fill.cxx b/src/plastimatch/base/volume_fill.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume_fill.h b/src/plastimatch/base/volume_fill.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume_grad.cxx b/src/plastimatch/base/volume_grad.cxx
old mode 100755
new mode 100644
index 9216fbc..7cd8ab4
--- a/src/plastimatch/base/volume_grad.cxx
+++ b/src/plastimatch/base/volume_grad.cxx
@@ -133,21 +133,19 @@ volume_calc_grad_mag (Volume* vout, const Volume* vref)
     lprintf ("volume_calc_grad_mag complete.\n");
 }
 
-#if defined (commentout)
 Volume::Pointer
-volume_make_gradient (Volume* ref)
+volume_gradient (const Volume::Pointer& ref)
 {
     Volume::Pointer grad = Volume::New (
         ref->dim, ref->origin, ref->spacing, 
 	ref->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3);
-    volume_calc_grad (grad.get(), ref);
+    volume_calc_grad (grad.get(), ref.get());
 
     return grad;
 }
-#endif
 
 Volume* 
-volume_make_gradient (Volume* ref)
+volume_make_gradient (const Volume* ref)
 {
     Volume* grad = new Volume (
         ref->dim, ref->origin, ref->spacing, 
diff --git a/src/plastimatch/base/volume_grad.h b/src/plastimatch/base/volume_grad.h
old mode 100755
new mode 100644
index 4bdbd8f..e4647ef
--- a/src/plastimatch/base/volume_grad.h
+++ b/src/plastimatch/base/volume_grad.h
@@ -8,8 +8,8 @@
 
 #include "volume.h"
 
-PLMBASE_API Volume* volume_make_gradient (Volume* ref);
-//PLMBASE_API Volume::Pointer volume_make_gradient (Volume* ref);
+PLMBASE_API Volume* volume_make_gradient (const Volume* ref);
+PLMBASE_API Volume::Pointer volume_gradient (const Volume::Pointer& ref);
 PLMBASE_API Volume::Pointer volume_gradient_magnitude (
     const Volume::Pointer& ref);
 
diff --git a/src/plastimatch/base/volume_header.cxx b/src/plastimatch/base/volume_header.cxx
index 4ca32dc..43e6d7a 100644
--- a/src/plastimatch/base/volume_header.cxx
+++ b/src/plastimatch/base/volume_header.cxx
@@ -68,6 +68,17 @@ Volume_header::Volume_header (
     d_ptr->m_direction_cosines.set (pih->GetDirection());
 }
 
+Volume_header::Volume_header (
+    const Plm_image::Pointer& img)
+{
+    this->d_ptr = new Volume_header_private;
+    Plm_image_header pih (img);
+    pih.get_dim (d_ptr->m_dim);
+    pih.get_origin (d_ptr->m_origin);
+    pih.get_spacing (d_ptr->m_spacing);
+    d_ptr->m_direction_cosines.set (pih.GetDirection());
+}
+
 Volume_header::~Volume_header ()
 {
     delete this->d_ptr;
diff --git a/src/plastimatch/base/volume_header.h b/src/plastimatch/base/volume_header.h
index 52d8e09..e4eede6 100644
--- a/src/plastimatch/base/volume_header.h
+++ b/src/plastimatch/base/volume_header.h
@@ -6,6 +6,7 @@
 
 #include "plmbase_config.h"
 #include "direction_cosines.h"
+#include "plm_image.h"
 #include "volume.h"
 
 class Bspline_xform;
@@ -24,6 +25,7 @@ public:
         float direction_cosines[9]);
     Volume_header (const Volume::Pointer& vol);
     Volume_header (const Plm_image_header *pih);
+    Volume_header (const Plm_image::Pointer& img);
     ~Volume_header ();
 
 public:
diff --git a/src/plastimatch/base/volume_limit.h b/src/plastimatch/base/volume_limit.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume_macros.h b/src/plastimatch/base/volume_macros.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume_resample.cxx b/src/plastimatch/base/volume_resample.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume_stats.cxx b/src/plastimatch/base/volume_stats.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/volume_stats.h b/src/plastimatch/base/volume_stats.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xform_convert.cxx b/src/plastimatch/base/xform_convert.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xform_convert.h b/src/plastimatch/base/xform_convert.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xform_legacy.cxx b/src/plastimatch/base/xform_legacy.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xform_legacy.h b/src/plastimatch/base/xform_legacy.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_ct.cxx b/src/plastimatch/base/xio_ct.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_ct_transform.cxx b/src/plastimatch/base/xio_ct_transform.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_ct_transform.h b/src/plastimatch/base/xio_ct_transform.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_demographic.cxx b/src/plastimatch/base/xio_demographic.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_demographic.h b/src/plastimatch/base/xio_demographic.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_dir.cxx b/src/plastimatch/base/xio_dir.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_patient.cxx b/src/plastimatch/base/xio_patient.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_patient.h b/src/plastimatch/base/xio_patient.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/base/xio_structures.cxx b/src/plastimatch/base/xio_structures.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/CMakeLists.txt b/src/plastimatch/cli/CMakeLists.txt
index 03c4cbf..f4d245f 100644
--- a/src/plastimatch/cli/CMakeLists.txt
+++ b/src/plastimatch/cli/CMakeLists.txt
@@ -23,14 +23,16 @@ set (PLASTIMATCH_SRC
   pcmd_adjust.cxx 
   pcmd_autolabel_train.cxx 
   pcmd_autolabel.cxx 
+  pcmd_bbox.cxx pcmd_bbox.h
   pcmd_benchmark.cxx 
-  pcmd_boundary.cxx 
+  pcmd_boundary.cxx pcmd_boundary.h
   pcmd_compare.cxx 
   pcmd_compose.cxx 
   pcmd_crop.cxx 
   pcmd_dice.cxx 
   pcmd_diff.cxx 
   pcmd_dmap.cxx
+  pcmd_dose.cxx pcmd_dose.h
   pcmd_drr.cxx 
   pcmd_dvh.cxx 
   pcmd_filter.cxx
@@ -55,6 +57,7 @@ set (PLASTIMATCH_SRC
   pcmd_threshold.cxx
   pcmd_thumbnail.cxx 
   pcmd_union.cxx
+  pcmd_vf_invert.cxx pcmd_vf_invert.h
   pcmd_warp.cxx 
   pcmd_warp_dij.cxx 
   pcmd_warp_pointset.cxx 
diff --git a/src/plastimatch/cli/pcmd_add.h b/src/plastimatch/cli/pcmd_add.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_adjust.cxx b/src/plastimatch/cli/pcmd_adjust.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_adjust.h b/src/plastimatch/cli/pcmd_adjust.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_autolabel.cxx b/src/plastimatch/cli/pcmd_autolabel.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_autolabel.h b/src/plastimatch/cli/pcmd_autolabel.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_autolabel_train.cxx b/src/plastimatch/cli/pcmd_autolabel_train.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_autolabel_train.h b/src/plastimatch/cli/pcmd_autolabel_train.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_bbox.cxx b/src/plastimatch/cli/pcmd_bbox.cxx
new file mode 100644
index 0000000..f9c1bd4
--- /dev/null
+++ b/src/plastimatch/cli/pcmd_bbox.cxx
@@ -0,0 +1,130 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmcli_config.h"
+#include "itkImageRegionIteratorWithIndex.h"
+
+#include "itk_bbox.h"
+#include "itk_image_clone.h"
+#include "itk_image_save.h"
+#include "itk_image_type.h"
+#include "pcmd_bbox.h"
+#include "plm_clp.h"
+#include "plm_image.h"
+
+class Bbox_parms {
+public:
+    std::string input_fn;
+    std::string output_mask_fn;
+    float margin;
+    bool z_only;
+public:
+    Bbox_parms () {
+        margin = 0.f;
+        z_only = false;
+    }
+};
+
+void
+do_bbox (const Bbox_parms *parms)
+{
+    Plm_image pli (parms->input_fn);
+    UCharImageType::Pointer img = pli.itk_uchar();
+
+    float bbox[6];
+    itk_bbox (img, bbox);
+
+    bbox[0] -= parms->margin;
+    bbox[1] += parms->margin;
+    bbox[2] -= parms->margin;
+    bbox[3] += parms->margin;
+    bbox[4] -= parms->margin;
+    bbox[5] += parms->margin;
+    
+    printf ("%f %f %f %f %f %f\n",
+        bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]);
+
+    if (parms->output_mask_fn != "") {
+        UCharImageType::Pointer img_out = itk_image_clone_empty (img);
+        itk::ImageRegionIteratorWithIndex< UCharImageType >
+            it (img_out,  img_out->GetLargestPossibleRegion());
+        for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
+            FloatPoint3DType point;
+            UCharImageType::RegionType::IndexType idx = it.GetIndex();
+            img_out->TransformIndexToPhysicalPoint (idx, point);
+            if (point[2] < bbox[2*2+0] || point[2] > bbox[2*2+1])
+            {
+                continue;
+            }
+            if ((parms->z_only)
+                || (point[0] > bbox[0*2+0] && point[0] < bbox[0*2+1]
+                    && point[1] > bbox[1*2+0] && point[1] < bbox[1*2+1]))
+            {
+                it.Set (1);
+            }
+        }
+        itk_image_save (img_out, parms->output_mask_fn);
+    }
+}
+
+static void
+usage_fn (dlib::Plm_clp* parser, int argc, char *argv[])
+{
+    std::cout << "Usage: plastimatch bbox [options] input-file\n";
+    parser->print_options (std::cout);
+    std::cout << std::endl;
+}
+
+static void
+parse_fn (
+    Bbox_parms* parms, 
+    dlib::Plm_clp* parser, 
+    int argc, 
+    char* argv[]
+)
+{
+    /* Add --help, --version */
+    parser->add_default_options ();
+
+    /* Basic options */
+    parser->add_long_option ("", "output",
+	"Location of output image", 1, "");
+    parser->add_long_option ("", "margin",
+	"Expand bounding box by margin (mm, may be negative)", 1, "0");
+    parser->add_long_option ("", "z-only",
+	"When creating output image, only consider z axis", 0);
+
+    /* Parse options */
+    parser->parse (argc,argv);
+
+    /* Handle --help, --version */
+    parser->check_default_options ();
+
+    /* Check that all necessary inputs are given */
+    if (parser->number_of_arguments() != 1) {
+	throw (dlib::error (
+                "Error.  A single input file must be given."));
+    }
+
+    /* Get input file */
+    parms->input_fn = (*parser)[0];
+
+    /* Copy remaining values into parameter struct */
+    parms->margin = parser->get_float ("margin");
+    if (parser->have_option ("output")) {
+        parms->output_mask_fn = parser->get_string ("output");
+    }
+    if (parser->have_option ("z-only")) {
+        parms->z_only = true;
+    }
+}
+
+void
+do_command_bbox (int argc, char *argv[])
+{
+    Bbox_parms bbox_parms;
+
+    plm_clp_parse (&bbox_parms, &parse_fn, &usage_fn, argc, argv, 1);
+
+    do_bbox (&bbox_parms);
+}
diff --git a/src/plastimatch/cli/pcmd_drr.h b/src/plastimatch/cli/pcmd_bbox.h
old mode 100755
new mode 100644
similarity index 73%
copy from src/plastimatch/cli/pcmd_drr.h
copy to src/plastimatch/cli/pcmd_bbox.h
index 91002cf..d5056db
--- a/src/plastimatch/cli/pcmd_drr.h
+++ b/src/plastimatch/cli/pcmd_bbox.h
@@ -1,10 +1,10 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _pcmd_drr_h_
-#define _pcmd_drr_h_
+#ifndef _pcmd_bbox_h_
+#define _pcmd_bbox_h_
 
 void
-do_command_drr (int argc, char *argv[]);
+do_command_bbox (int argc, char *argv[]);
 
 #endif
diff --git a/src/plastimatch/cli/pcmd_benchmark.cxx b/src/plastimatch/cli/pcmd_benchmark.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_benchmark.h b/src/plastimatch/cli/pcmd_benchmark.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_boundary.cxx b/src/plastimatch/cli/pcmd_boundary.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_boundary.h b/src/plastimatch/cli/pcmd_boundary.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_compare.cxx b/src/plastimatch/cli/pcmd_compare.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_compare.h b/src/plastimatch/cli/pcmd_compare.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_compose.cxx b/src/plastimatch/cli/pcmd_compose.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_compose.h b/src/plastimatch/cli/pcmd_compose.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_crop.cxx b/src/plastimatch/cli/pcmd_crop.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_crop.h b/src/plastimatch/cli/pcmd_crop.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dice.cxx b/src/plastimatch/cli/pcmd_dice.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dice.h b/src/plastimatch/cli/pcmd_dice.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_diff.cxx b/src/plastimatch/cli/pcmd_diff.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_diff.h b/src/plastimatch/cli/pcmd_diff.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dmap.cxx b/src/plastimatch/cli/pcmd_dmap.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dmap.h b/src/plastimatch/cli/pcmd_dmap.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dose.cxx b/src/plastimatch/cli/pcmd_dose.cxx
new file mode 100644
index 0000000..abae3b5
--- /dev/null
+++ b/src/plastimatch/cli/pcmd_dose.cxx
@@ -0,0 +1,33 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmcli_config.h"
+#include <stdlib.h>
+
+#include "logfile.h"
+#include "pcmd_dose.h"
+#include "plm_return_code.h"
+#include "plm_timer.h"
+#include "rt_plan.h"
+
+void
+do_command_dose (int argc, char* argv[])
+{
+
+    if (argc < 3) {
+        lprintf ("Usage: plastimatch dose command_file\n");
+        exit (1);
+    }
+
+    char *command_file = argv[2];
+
+    Plm_timer timer;
+    Rt_plan plan;
+    timer.start ();
+    if (plan.set_command_file (command_file) != PLM_SUCCESS) {
+        lprintf ("Error parsing command file.\n");
+        return;
+    }
+    plan.compute_plan ();
+    lprintf ("Total execution time : %f secondes.\n", timer.report ());
+}
diff --git a/src/plastimatch/cli/pcmd_add.h b/src/plastimatch/cli/pcmd_dose.h
old mode 100755
new mode 100644
similarity index 74%
copy from src/plastimatch/cli/pcmd_add.h
copy to src/plastimatch/cli/pcmd_dose.h
index d5b7913..9641386
--- a/src/plastimatch/cli/pcmd_add.h
+++ b/src/plastimatch/cli/pcmd_dose.h
@@ -1,11 +1,11 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _pcmd_add_h_
-#define _pcmd_add_h_
+#ifndef _pcmd_dose_h_
+#define _pcmd_dose_h_
 
 #include "plmcli_config.h"
 
-void do_command_add (int argc, char *argv[]);
+void do_command_dose (int argc, char *argv[]);
 
 #endif
diff --git a/src/plastimatch/cli/pcmd_drr.cxx b/src/plastimatch/cli/pcmd_drr.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_drr.h b/src/plastimatch/cli/pcmd_drr.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dvh.cxx b/src/plastimatch/cli/pcmd_dvh.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_dvh.h b/src/plastimatch/cli/pcmd_dvh.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_filter.cxx b/src/plastimatch/cli/pcmd_filter.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_filter.h b/src/plastimatch/cli/pcmd_filter.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_gamma.cxx b/src/plastimatch/cli/pcmd_gamma.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_gamma.h b/src/plastimatch/cli/pcmd_gamma.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_header.cxx b/src/plastimatch/cli/pcmd_header.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_header.h b/src/plastimatch/cli/pcmd_header.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_mabs.cxx b/src/plastimatch/cli/pcmd_mabs.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_mabs.h b/src/plastimatch/cli/pcmd_mabs.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_mask.cxx b/src/plastimatch/cli/pcmd_mask.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_mask.h b/src/plastimatch/cli/pcmd_mask.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_probe.h b/src/plastimatch/cli/pcmd_probe.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_register.cxx b/src/plastimatch/cli/pcmd_register.cxx
index e226913..e69caed 100644
--- a/src/plastimatch/cli/pcmd_register.cxx
+++ b/src/plastimatch/cli/pcmd_register.cxx
@@ -3,7 +3,9 @@
    ----------------------------------------------------------------------- */
 #include "plmcli_config.h"
 
+#include "logfile.h"
 #include "pcmd_register.h"
+#include "plm_return_code.h"
 #include "registration.h"
 
 void
@@ -23,9 +25,12 @@ do_command_register (int argc, char* argv[])
     }
 
     Registration reg;
-    if (reg.set_command_file (command_filename) < 0) {
-        printf ("Error.  could not load %s as command file.\n", 
+    Plm_return_code rc = reg.set_command_file (command_filename);
+    if (rc != PLM_SUCCESS) {
+        logfile_printf ("Error.  Could not load %s as command file.\n", 
             command_filename);
+        exit (1);
     }
+
     reg.do_registration ();
 }
diff --git a/src/plastimatch/cli/pcmd_scale.h b/src/plastimatch/cli/pcmd_scale.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_segment.cxx b/src/plastimatch/cli/pcmd_segment.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_segment.h b/src/plastimatch/cli/pcmd_segment.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_sift.h b/src/plastimatch/cli/pcmd_sift.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_stats.cxx b/src/plastimatch/cli/pcmd_stats.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_stats.h b/src/plastimatch/cli/pcmd_stats.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_synth.cxx b/src/plastimatch/cli/pcmd_synth.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_synth.h b/src/plastimatch/cli/pcmd_synth.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_synth_vf.cxx b/src/plastimatch/cli/pcmd_synth_vf.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_synth_vf.h b/src/plastimatch/cli/pcmd_synth_vf.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_threshold.cxx b/src/plastimatch/cli/pcmd_threshold.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_threshold.h b/src/plastimatch/cli/pcmd_threshold.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_thumbnail.cxx b/src/plastimatch/cli/pcmd_thumbnail.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_thumbnail.h b/src/plastimatch/cli/pcmd_thumbnail.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_union.h b/src/plastimatch/cli/pcmd_union.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/vf_invert_main.cxx b/src/plastimatch/cli/pcmd_vf_invert.cxx
old mode 100755
new mode 100644
similarity index 88%
copy from src/plastimatch/standalone/vf_invert_main.cxx
copy to src/plastimatch/cli/pcmd_vf_invert.cxx
index e461c4e..e9527a6
--- a/src/plastimatch/standalone/vf_invert_main.cxx
+++ b/src/plastimatch/cli/pcmd_vf_invert.cxx
@@ -1,19 +1,15 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#include "plm_config.h"
-#include "itkImage.h"
+#include "plmcli_config.h"
 
 #include "itk_image_load.h"
 #include "mha_io.h"
 #include "plm_clp.h"
-#include "plm_int.h"
 #include "plm_image.h"
 #include "plm_image_header.h"
-#include "plm_math.h"
 #include "vf_convolve.h"
 #include "vf_invert.h"
-#include "volume.h"
 
 class Vf_invert_parms {
 public:
@@ -46,36 +42,6 @@ public:
     }
 };
 
-#if defined (commentout)
-void
-vf_invert_itk (Vf_Invert_Parms* parms)
-{
-    typedef itk::InverseDeformationFieldImageFilter < DeformationFieldType, DeformationFieldType >  FilterType;
-    
-    Plm_image_header pih;
-
-    if (parms->fixed_img_fn[0]) {
-        /* if given, use the parameters from user-supplied fixed image */
-        FloatImageType::Pointer fixed = load_float (parms->fixed_img_fn);
-        pih.set_from_itk_image (fixed);
-    } else {
-        pih.set_from_gpuit (parms->origin, parms->spacing, parms->dim);
-    }
-
-    FilterType::Pointer filter = FilterType::New ();
-    DeformationFieldType::Pointer vf_in = load_float_field (parms->vf_in_fn);
-    filter->SetInput (vf_in);
-    filter->SetOutputOrigin (pih.origin);
-    filter->SetOutputSpacing (pih.spacing);
-    filter->SetSize (pih.m_region.GetSize());
-
-    //filter->SetOutsideValue( 0 );
-    filter->Update();
-    DeformationFieldType::Pointer vf_out = filter->GetOutput();
-    save_image (vf_out, parms->vf_out_fn);
-}
-#endif
-
 void
 do_vf_invert_old (Vf_invert_parms* parms)
 {
@@ -245,7 +211,8 @@ do_vf_invert (Vf_invert_parms* parms)
 static void
 usage_fn (dlib::Plm_clp* parser, int argc, char *argv[])
 {
-    std::cout << "Usage: vf_invert [options]\n";
+    printf ("Usage: plastimatch %s [options] input_file [input_file ...]\n", 
+        argv[1]);
     parser->print_options (std::cout);
     std::cout << std::endl;
 }
@@ -335,14 +302,14 @@ parse_fn (
     }
 }
 
-int
-main (int argc, char *argv[])
+void
+do_command_vf_invert (int argc, char *argv[])
 {
     Vf_invert_parms parms;
     
-    plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv);
-    do_vf_invert (&parms);
+    /* Parse command line parameters */
+    plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1);
 
-    printf ("Finished!\n");
-    return 0;
+    /* Do the work */
+    do_vf_invert (&parms);
 }
diff --git a/src/plastimatch/cli/pcmd_add.h b/src/plastimatch/cli/pcmd_vf_invert.h
old mode 100755
new mode 100644
similarity index 71%
copy from src/plastimatch/cli/pcmd_add.h
copy to src/plastimatch/cli/pcmd_vf_invert.h
index d5b7913..d43f632
--- a/src/plastimatch/cli/pcmd_add.h
+++ b/src/plastimatch/cli/pcmd_vf_invert.h
@@ -1,11 +1,11 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _pcmd_add_h_
-#define _pcmd_add_h_
+#ifndef _pcmd_vf_invert_h_
+#define _pcmd_vf_invert_h_
 
 #include "plmcli_config.h"
 
-void do_command_add (int argc, char *argv[]);
+void do_command_vf_invert (int argc, char *argv[]);
 
 #endif
diff --git a/src/plastimatch/cli/pcmd_warp.cxx b/src/plastimatch/cli/pcmd_warp.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_warp.h b/src/plastimatch/cli/pcmd_warp.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_warp_pointset.cxx b/src/plastimatch/cli/pcmd_warp_pointset.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_xf_convert.cxx b/src/plastimatch/cli/pcmd_xf_convert.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_xf_convert.h b/src/plastimatch/cli/pcmd_xf_convert.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_xio_dvh.cxx b/src/plastimatch/cli/pcmd_xio_dvh.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/pcmd_xio_dvh.h b/src/plastimatch/cli/pcmd_xio_dvh.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cli/plastimatch_main.cxx b/src/plastimatch/cli/plastimatch_main.cxx
index 7c6a4f4..37ae1ae 100644
--- a/src/plastimatch/cli/plastimatch_main.cxx
+++ b/src/plastimatch/cli/plastimatch_main.cxx
@@ -10,6 +10,7 @@
 #include "pcmd_adjust.h"
 #include "pcmd_autolabel.h"
 #include "pcmd_autolabel_train.h"
+#include "pcmd_bbox.h"
 #include "pcmd_benchmark.h"
 #include "pcmd_boundary.h"
 #include "pcmd_compare.h"
@@ -18,6 +19,7 @@
 #include "pcmd_dice.h"
 #include "pcmd_diff.h"
 #include "pcmd_dmap.h"
+#include "pcmd_dose.h"
 #include "pcmd_drr.h"
 #include "pcmd_dvh.h"
 #include "pcmd_filter.h"
@@ -42,6 +44,7 @@
 #include "pcmd_threshold.h"
 #include "pcmd_thumbnail.h"
 #include "pcmd_union.h"
+#include "pcmd_vf_invert.h"
 #include "pcmd_warp.h"
 #include "pcmd_xf_convert.h"
 #include "pcmd_xio_dvh.h"
@@ -66,48 +69,52 @@ print_usage (int return_code)
         "  adjust      "
 //        "  autolabel   "
         "  average     "
+        "  bbox        "
 //        "  benchmark   "
         "  boundary    "
-        "  crop        "
         "\n"
+        "  crop        "
         "  compare     "
         "  compose     "
         "  convert     "
         "  dice        "
-        "  diff        "
         "\n"
+        "  diff        "
         "  dmap        "
+        "  dose        "
 //        "  drr         "
         "  dvh         "
         "  fill        "
+        "\n"
         "  filter      "
         "  gamma       "
-        "\n"
         "  header      "
         "  jacobian    "
         "  mabs        "
+        "\n"
         "  mask        "
         "  maximum     "
-        "\n"
         "  ml-convert  "
         "  multiply    "
         "  probe       "
+        "\n"
         "  register    "
         "  resample    "
-        "\n"
         "  scale       "
         "  segment     "
 //        "  sift        "
         "  stats       "
+        "\n"
         "  synth       "
         "  synth-vf    "
-        "\n"
         "  threshold   "
         "  thumbnail   "
         "  union       "
+        "\n"
+        "  vf-invert   "
         "  warp        "
-        "  xf-convert  "
 //        "  xio-dvh     "
+        "  xf-convert  "
         "\n"
         "\n"
         "For detailed usage of a specific command, type:\n"
@@ -146,6 +153,9 @@ do_command (int argc, char* argv[])
     else if (!strcmp (command, "autolabel-train")) {
         do_command_autolabel_train (argc, argv);
     }
+    else if (!strcmp (command, "bbox")) {
+        do_command_bbox (argc, argv);
+    }
     else if (!strcmp (command, "benchmark")) {
         do_command_benchmark (argc, argv);
     }
@@ -171,6 +181,9 @@ do_command (int argc, char* argv[])
     else if (!strcmp (command, "diff")) {
         do_command_diff (argc, argv);
     }
+    else if (!strcmp (command, "dose")) {
+        do_command_dose (argc, argv);
+    }
     else if (!strcmp (command, "drr")) {
         do_command_drr (argc, argv);
     }
@@ -256,6 +269,9 @@ do_command (int argc, char* argv[])
     else if (!strcmp (command, "union")) {
         do_command_union (argc, argv);
     }
+    else if (!strcmp (command, "vf-invert")) {
+        do_command_vf_invert (argc, argv);
+    }
     else if (!strcmp (command, "warp")) {
         /* convert and warp are the same */
         do_command_warp (argc, argv);
diff --git a/src/plastimatch/clp/CMakeLists.txt b/src/plastimatch/clp/CMakeLists.txt
old mode 100755
new mode 100644
diff --git a/src/plastimatch/clp/plm_clp.cxx b/src/plastimatch/clp/plm_clp.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/clp/plm_clp.h b/src/plastimatch/clp/plm_clp.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/cuda/cuda_probe.h b/src/plastimatch/cuda/cuda_probe.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/dose/CMakeLists.txt b/src/plastimatch/dose/CMakeLists.txt
old mode 100644
new mode 100755
index 12582d0..9a0579c
--- a/src/plastimatch/dose/CMakeLists.txt
+++ b/src/plastimatch/dose/CMakeLists.txt
@@ -14,22 +14,27 @@ include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
 ##  SOURCE FILES
 ##-----------------------------------------------------------------------------
 set (PLMDOSE_LIBRARY_SRC
-  bragg_curve.cxx
-  dose_volume_functions.cxx
+  bragg_curve.cxx bragg_curve.h
+  dose_volume_functions.cxx dose_volume_functions.h
   particle_type.cxx particle_type.h 
-  rt_beam.cxx
-  rt_depth_dose.cxx
-  rt_dose.cxx
-  rt_lut.cxx
-  rt_mebs.cxx
-  rt_parms.cxx
-  rt_plan.cxx  
-  rt_sigma.cxx
-  wed_parms.cxx
+  rt_beam.cxx rt_beam.h
+  rt_beam_model.cxx rt_beam_model.h
+  rt_depth_dose.cxx rt_depth_dose.h
+  rt_dij.cxx rt_dij.h
+  rt_dose.cxx rt_dose.h
+  rt_dose_timing.h
+  rt_lut.cxx rt_lut.h
+  rt_spot_map.cxx rt_spot_map.h 
+  rt_mebs.cxx rt_mebs.h
+  rt_parms.cxx rt_parms.h
+  rt_plan.cxx rt_plan.h
+  rt_sigma.cxx rt_sigma.h
+  wed_parms.cxx wed_parms.h
   )
 
 set (PLMDOSE_LIBRARY_DEPENDENCIES 
   plmbase
+  plmutil
   plmsys
   )
 
diff --git a/src/plastimatch/dose/dose_volume_functions.cxx b/src/plastimatch/dose/dose_volume_functions.cxx
old mode 100644
new mode 100755
index d27b49d..f6bf6bd
--- a/src/plastimatch/dose/dose_volume_functions.cxx
+++ b/src/plastimatch/dose/dose_volume_functions.cxx
@@ -1,13 +1,18 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-
+#include "plmdose_config.h"
 #include "dose_volume_functions.h"
 #include "proj_volume.h"
 #include "ray_data.h"
 #include "rt_lut.h"
 
-void dose_volume_create(Volume* dose_volume, float* sigma_max, Rpl_volume* volume, double range)
+void
+dose_volume_create (
+    Volume* dose_volume,
+    float* sigma_max,
+    Rpl_volume* volume,
+    double range)
 {
     /* we want to add extra margins around our volume take into account the dose that will be scattered outside of the rpl_volume */
     /* A 3 sigma margin is applied to the front_back volume, and the size of our volume will be the projection of this shape on the back_clipping_plane */
@@ -18,7 +23,6 @@ void dose_volume_create(Volume* dose_volume, float* sigma_max, Rpl_volume* volum
     plm_long dim[3] = {0,0,0};
     float origin[3] = {0,0,0};
     float spacing[3] = {0,0,0};
-    plm_long npix = 0;
     const float dc[9] = {
         dose_volume->get_direction_cosines()[0], dose_volume->get_direction_cosines()[1], dose_volume->get_direction_cosines()[2], 
         dose_volume->get_direction_cosines()[3], dose_volume->get_direction_cosines()[4], dose_volume->get_direction_cosines()[5], 
@@ -55,12 +59,13 @@ void dose_volume_create(Volume* dose_volume, float* sigma_max, Rpl_volume* volum
             dim[i] = (plm_long) ((back_clip_useful - volume->get_front_clipping_plane())/spacing[i] + 1);
         }
     }
-    npix = dim[0]*dim[1]*dim[2];
     dose_volume->create(dim, origin, spacing, dc, PT_FLOAT,1);
 }
 
 void
-calculate_rpl_coordinates_xyz(std::vector<std:: vector<double> >* xyz_coordinates_volume, Rpl_volume* rpl_volume)
+calculate_rpl_coordinates_xyz (
+    std::vector<std:: vector<double> >* xyz_coordinates_volume,
+    Rpl_volume* rpl_volume)
 {
     double aperture[3] = {0.0,0.0,0.0};
     double entrance[3] = {0.0,0.0,0.0};
@@ -75,7 +80,7 @@ calculate_rpl_coordinates_xyz(std::vector<std:: vector<double> >* xyz_coordinate
         for (int j = 0; j < rpl_volume->get_vol()->dim[1];j++){
         
             idx2d = j * dim[0] + i;
-            Ray_data* ray_data = &rpl_volume->get_Ray_data()[idx2d];
+            Ray_data* ray_data = &rpl_volume->get_ray_data()[idx2d];
 
             vec3_cross(vec_antibug_prt, rpl_volume->get_aperture()->pdn, rpl_volume->get_proj_volume()->get_nrm());
             ray_bev[0] = vec3_dot(ray_data->ray, vec_antibug_prt);
@@ -100,7 +105,7 @@ calculate_rpl_coordinates_xyz(std::vector<std:: vector<double> >* xyz_coordinate
 
 void 
 dose_volume_reconstruction (
-    Rpl_volume* rpl_dose_vol, 
+    Rpl_volume* dose_rv, 
     Volume::Pointer dose_vol
 )
 {
@@ -111,7 +116,7 @@ dose_volume_reconstruction (
     double dose = 0;
 
     float* dose_img = (float*) dose_vol->img;
-
+    bool first = true;
     for (ct_ijk[2] = 0; ct_ijk[2] < dose_vol->dim[2]; ct_ijk[2]++) {
         for (ct_ijk[1] = 0; ct_ijk[1] < dose_vol->dim[1]; ct_ijk[1]++) {
             for (ct_ijk[0] = 0; ct_ijk[0] < dose_vol->dim[0]; ct_ijk[0]++) {
@@ -123,7 +128,7 @@ dose_volume_reconstruction (
                 ct_xyz[2] = (double) (dose_vol->origin[2] + ct_ijk[2] * dose_vol->spacing[2]);
                 ct_xyz[3] = (double) 1.0;
                 idx = volume_index (dose_vol->dim, ct_ijk);
-                dose = rpl_dose_vol->get_rgdepth(ct_xyz);
+                dose = dose_rv->get_value(ct_xyz);
 
                 if (dose <= 0) {
                     continue;
@@ -136,7 +141,12 @@ dose_volume_reconstruction (
     }
 }
 
-void build_hong_grid(std::vector<double>* area, std::vector<double>* xy_grid, int radius_sample, int theta_sample)
+void
+build_hong_grid (
+    std::vector<double>* area,
+    std::vector<double>* xy_grid,
+    int radius_sample,
+    int theta_sample)
 {
     double dr = 1.0 / (double) radius_sample;
     double dt = 2.0 * M_PI / (double) theta_sample;
@@ -197,7 +207,7 @@ find_xyz_from_ijk(double* xyz, Volume* volume, int* ijk)
     xyz[2] = volume->origin[2] + ijk[2]*volume->spacing[2];
 }
 
-double erf_gauss(double x)
+double erf_gauss (double x)
 {
     int sign = 1;
     if (x < 0) {sign = -1;}
@@ -209,7 +219,9 @@ double erf_gauss(double x)
     return sign*y;
 }
 
-double double_gaussian_interpolation(double* gaussian_center, double* pixel_center, double sigma, double* spacing)
+double
+double_gaussian_interpolation (
+    double* gaussian_center, double* pixel_center, double sigma, double* spacing)
 {
     double x1 = pixel_center[0] - 0.5 * spacing[0];
     double x2 = x1 + spacing[0];
@@ -230,50 +242,49 @@ double get_off_axis(double radius, double dr, double sigma)
 /* MD Fix: don't consider any cosines directions */
 void dose_normalization_to_dose(Volume::Pointer dose_volume, double dose, Rt_beam* beam)
 {
-	int idx = 0;
-	double norm = 0;
-	int ijk_max[3] = {0,0,0};
-	float* img = (float*) dose_volume->img;
-
-	for(int i = 0; i < dose_volume->dim[0]; i++)
-	{
-		for(int j = 0; j < dose_volume->dim[1]; j++)
-		{
-			for(int k = 0; k < dose_volume->dim[2]; k++)
-			{
-				idx = i + (dose_volume->dim[0] * (j + dose_volume->dim[1] * k));
-
-				if (img[idx] > norm)
-				{
-					norm = img[idx];
-					ijk_max[0] = i;
-					ijk_max[1] = j;
-					ijk_max[2] = k;
-				}
-			}
-		}
-	}
-	if (norm > 0)
-	{
-		for (int i = 0; i < dose_volume->dim[0] * dose_volume->dim[1] * dose_volume->dim[2]; i++)
-		{
-			img[i] = img[i] / norm * dose;
-		}
-    int ap_dim[2] = {beam->get_aperture()->get_dim(0),beam->get_aperture()->get_dim(1)};
-    beam->get_mebs()->scale_num_part(dose/norm, ap_dim);
-
-		printf("Raw dose at the maximum (%lg, %lg, %lg) : %lg A.U.\nDose normalized at the maximum to ", dose_volume->origin[0] + ijk_max[0] * dose_volume->spacing[0], dose_volume->origin[1] + ijk_max[1] * dose_volume->spacing[1], dose_volume->origin[2] + ijk_max[2] * dose_volume->spacing[2], norm);
-	}
-	else
-	{
-		printf("Dose is null in the entire volume. Please check your input conditions.\n");
-	}
+    int idx = 0;
+    double norm = 0;
+    int ijk_max[3] = {0,0,0};
+    float* img = (float*) dose_volume->img;
+
+    for(int i = 0; i < dose_volume->dim[0]; i++)
+    {
+        for(int j = 0; j < dose_volume->dim[1]; j++)
+        {
+            for(int k = 0; k < dose_volume->dim[2]; k++)
+            {
+                idx = i + (dose_volume->dim[0] * (j + dose_volume->dim[1] * k));
+
+                if (img[idx] > norm)
+                {
+                    norm = img[idx];
+                    ijk_max[0] = i;
+                    ijk_max[1] = j;
+                    ijk_max[2] = k;
+                }
+            }
+        }
+    }
+    if (norm > 0)
+    {
+        for (int i = 0; i < dose_volume->dim[0] * dose_volume->dim[1] * dose_volume->dim[2]; i++)
+        {
+            img[i] = img[i] / norm * dose;
+        }
+        int ap_dim[2] = {beam->get_aperture()->get_dim(0),beam->get_aperture()->get_dim(1)};
+        beam->get_mebs()->scale_num_part(dose/norm, ap_dim);
+
+        printf("Raw dose at the maximum (%lg, %lg, %lg) : %lg A.U.\nDose normalized at the maximum to ", dose_volume->origin[0] + ijk_max[0] * dose_volume->spacing[0], dose_volume->origin[1] + ijk_max[1] * dose_volume->spacing[1], dose_volume->origin[2] + ijk_max[2] * dose_volume->spacing[2], norm);
+    }
+    else
+    {
+        printf("Dose is null in the entire volume. Please check your input conditions.\n");
+    }
 }
 
 /* MD Fix: don't consider any cosines directions */
 void dose_normalization_to_dose_and_point(Volume::Pointer dose_volume, double dose, const float* rdp_ijk, const float* rdp, Rt_beam* beam)
 {
-    std::vector<float>& num_part = beam->get_mebs()->get_num_particles();
     double norm = dose_volume->get_ijk_value(rdp_ijk);
     float* img = (float*) dose_volume->img;
 
@@ -289,7 +300,7 @@ void dose_normalization_to_dose_and_point(Volume::Pointer dose_volume, double do
     }
     else
     {
-        printf("***WARNING***\nDose null at the reference dose point.\nDose normalized to the dose maximum in the volume.\n");
+        printf("Dose null at the reference dose point.\nDose normalized to the dose maximum in the volume.\n");
         dose_normalization_to_dose(dose_volume, dose,beam);
     }
 }
diff --git a/src/plastimatch/dose/dose_volume_functions.h b/src/plastimatch/dose/dose_volume_functions.h
old mode 100644
new mode 100755
index d17cad9..91b62c8
--- a/src/plastimatch/dose/dose_volume_functions.h
+++ b/src/plastimatch/dose/dose_volume_functions.h
@@ -11,7 +11,7 @@
 void dose_volume_create(Volume* dose_volume, float* sigma_max, Rpl_volume* volume, double range);
 
 void calculate_rpl_coordinates_xyz(std::vector<std::vector<double> >* xyz_coordinates_volume, Rpl_volume* rpl_volume);
-void dose_volume_reconstruction(Rpl_volume* rpl_dose_vol, Volume::Pointer dose_vol);
+void dose_volume_reconstruction(Rpl_volume* dose_rv, Volume::Pointer dose_vol);
 
 void build_hong_grid(std::vector<double>* area, std::vector<double>* xy_grid, int radius_sample, int theta_sample);
 
@@ -29,4 +29,4 @@ double get_off_axis(double radius, double dr, double sigma);
 void dose_normalization_to_dose(Volume::Pointer dose_volume, double dose, Rt_beam* beam);
 void dose_normalization_to_dose_and_point(Volume::Pointer dose_volume, double dose, const float* rdp_ijk, const float* rdp, Rt_beam* beam);
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/plastimatch/dose/rt_beam.cxx b/src/plastimatch/dose/rt_beam.cxx
old mode 100644
new mode 100755
index 0841b45..a940ffd
--- a/src/plastimatch/dose/rt_beam.cxx
+++ b/src/plastimatch/dose/rt_beam.cxx
@@ -2,7 +2,6 @@
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
 #include "plmdose_config.h"
-#include "proj_volume.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -10,8 +9,39 @@
 #include <math.h>
 
 #include "bragg_curve.h"
+#include "plm_math.h"
+#include "proj_volume.h"
 #include "rt_beam.h"
+#include "rt_dose_timing.h"
 #include "rt_plan.h"
+#include "rt_spot_map.h"
+
+static void
+save_vector_as_image (
+    const std::vector<double>& v,
+    const int dim2d[2],
+    const std::string& filename)
+{
+    plm_long dim[3] = { dim2d[0], dim2d[1], 1 };
+    float origin[3] = { 0.f, 0.f, 0.f };
+    float spacing[3] = { 1.f, 1.f, 1.f };
+    Volume::Pointer vol = Volume::New (
+        dim, origin, spacing, (float*) 0, PT_FLOAT, 1);
+    float *vol_img = vol->get_raw<float> ();
+
+    for (plm_long i = 0; i < vol->npix; i++)
+    {
+        if (std::isnan(v[i]) || std::isinf(v[i]) || v[i] == NLMAX(double)) {
+            vol_img[i] = -1;
+        } else {
+            vol_img[i] = (float) v[i];
+        }
+    }
+
+    Plm_image::Pointer img = Plm_image::New (vol);
+    img->save_image (filename);
+}
+
 
 class Rt_beam_private {
 public:
@@ -21,22 +51,29 @@ public:
 
     double source[3];
     double isocenter[3];
-    char flavor;
+    std::string flavor;
     char homo_approx;
 
     float beamWeight;
 
+    Rt_spot_map::Pointer spot_map;
     Rt_mebs::Pointer mebs;
     std::string debug_dir;
 
     float smearing;
     char rc_MC_model;
     float source_size;
-
     float step_length;
 
-    Aperture::Pointer aperture;
+    double max_wed;
+    double min_wed;
+
+    Plm_image::Pointer ct_hu;
+    Plm_image::Pointer ct_psp;
     Plm_image::Pointer target;
+    Aperture::Pointer aperture;
+
+    Rt_dose_timing::Pointer rt_dose_timing;
 
     std::string aperture_in;
     std::string range_compensator_in;
@@ -44,9 +81,13 @@ public:
     std::string aperture_out;
     std::string proj_dose_out;
     std::string proj_img_out;
+    std::string proj_target_out;
     std::string range_compensator_out;
     std::string sigma_out;
     std::string wed_out;
+    std::string beam_dump_out;
+    std::string dij_out;
+    
     std::string beam_line_type;
 
 public:
@@ -60,24 +101,29 @@ public:
         this->isocenter[0] = 0.f;
         this->isocenter[1] = 0.f;
         this->isocenter[2] = 0.f;
-        this->flavor = 'a';
+        this->flavor = "a";
         this->homo_approx = 'n';
 
         this->beamWeight = 1.f;
+        this->spot_map = Rt_spot_map::New();
         this->mebs = Rt_mebs::New();
         this->debug_dir = "";
         this->smearing = 0.f;
         this->rc_MC_model = 'n';
         this->source_size = 0.f;
         this->step_length = 1.f;
+        this->min_wed = 0.;
+        this->max_wed = 0.;
 
         aperture = Aperture::New();
+        rt_dose_timing = Rt_dose_timing::New();
 
         this->aperture_in = "";
         this->range_compensator_in = "";
         this->aperture_out = "";
         this->proj_dose_out = "";
         this->proj_img_out = "";
+        this->proj_target_out = "";
         this->range_compensator_out = "";
         this->sigma_out = "";
         this->wed_out = "";
@@ -96,22 +142,30 @@ public:
         this->flavor = rtbp->flavor;
         this->homo_approx = rtbp->homo_approx;
 
-        /* Copy the mebs object */
         this->beamWeight = rtbp->beamWeight;
-        this->mebs = Rt_mebs::New (rtbp->mebs);
+        // Clear the spot map
+        this->spot_map = Rt_spot_map::New();
+        // Copy the mebs object (?)
+        this->mebs = Rt_mebs::New(rtbp->mebs);
         this->debug_dir = rtbp->debug_dir;
         this->smearing = rtbp->smearing;
         this->source_size = rtbp->source_size;
         this->step_length = rtbp->step_length;
+        this->min_wed = rtbp->min_wed;
+        this->max_wed = rtbp->max_wed;
 
         /* Copy the aperture object */
         aperture = Aperture::New (rtbp->aperture);
 
+        /* Share same timing object */
+        rt_dose_timing = rtbp->rt_dose_timing;
+
         this->aperture_in = rtbp->aperture_in;
         this->range_compensator_in = rtbp->range_compensator_in;
         this->aperture_out = rtbp->aperture_out;
         this->proj_dose_out = rtbp->proj_dose_out;
         this->proj_img_out = rtbp->proj_img_out;
+        this->proj_target_out = rtbp->proj_target_out;
         this->range_compensator_out = rtbp->range_compensator_out;
         this->sigma_out = rtbp->sigma_out;
         this->wed_out = rtbp->wed_out;
@@ -122,35 +176,15 @@ public:
 Rt_beam::Rt_beam ()
 {
     this->d_ptr = new Rt_beam_private();
-    this->rpl_vol = new Rpl_volume();
 
     /* Creation of the volumes useful for dose calculation */
-
-    if (this->get_flavor() == 'f')
-    {    
-        this->rpl_ct_vol_HU = new Rpl_volume();
-        this->sigma_vol = new Rpl_volume();
-    }
-
-    if (this->get_flavor() == 'g')
-    {    
-        this->rpl_ct_vol_HU = new Rpl_volume();
-        this->sigma_vol = new Rpl_volume();
-        this->rpl_vol_lg = new Rpl_volume();
-        this->rpl_ct_vol_HU_lg = new Rpl_volume();
-        this->sigma_vol_lg = new Rpl_volume();
-        this->rpl_dose_vol = new Rpl_volume();
-    }
-
-    if (this->get_flavor() == 'h')
-    {    
-        this->rpl_ct_vol_HU = new Rpl_volume();
-        this->sigma_vol = new Rpl_volume();
-        this->rpl_vol_lg = new Rpl_volume();
-        this->rpl_ct_vol_HU_lg = new Rpl_volume();
-        this->sigma_vol_lg = new Rpl_volume();
-        this->rpl_dose_vol = new Rpl_volume();
-    }
+    this->rsp_accum_vol = new Rpl_volume();
+    this->hu_samp_vol = 0;
+    this->sigma_vol = 0;
+    this->rpl_vol_lg = 0;
+    this->rpl_vol_samp_lg = 0;
+    this->sigma_vol_lg = 0;
+    this->dose_rv = 0;
 }
 
 Rt_beam::Rt_beam (const Rt_beam* rt_beam)
@@ -160,13 +194,13 @@ Rt_beam::Rt_beam (const Rt_beam* rt_beam)
     
     /* The below calculation volumes don't need to be copied 
        from input beam */
-    this->rpl_vol = 0;
-    this->rpl_ct_vol_HU = 0;
+    this->rsp_accum_vol = 0;
+    this->hu_samp_vol = 0;
     this->sigma_vol = 0;
     this->rpl_vol_lg = 0;
-    this->rpl_ct_vol_HU_lg = 0;
+    this->rpl_vol_samp_lg = 0;
     this->sigma_vol_lg = 0;
-    this->rpl_dose_vol = 0;
+    this->dose_rv = 0;
 }
 
 Rt_beam::~Rt_beam ()
@@ -256,14 +290,14 @@ Rt_beam::get_source_distance () const
     return vec3_dist (d_ptr->isocenter, d_ptr->source);
 }
 
-char
+const std::string&
 Rt_beam::get_flavor (void) const
 {
     return d_ptr->flavor;
 }
 
 void
-Rt_beam::set_flavor (char flavor)
+Rt_beam::set_flavor (const std::string& flavor)
 {
     d_ptr->flavor = flavor;
 }
@@ -277,13 +311,13 @@ Rt_beam::get_homo_approx () const
 void 
 Rt_beam::set_homo_approx (char homo_approx)
 {
-	d_ptr->homo_approx = homo_approx;
+    d_ptr->homo_approx = homo_approx;
 }
 
 Rt_mebs::Pointer
 Rt_beam::get_mebs()
 {
-	return d_ptr->mebs;
+    return d_ptr->mebs;
 }
 
 float
@@ -334,116 +368,235 @@ Rt_beam::dump (const char* dir)
     d_ptr->mebs->dump (dir);
 }
 
+void
+Rt_beam::dump (const std::string& dir)
+{
+    this->dump (dir.c_str());
+}
+
 void 
-Rt_beam::compute_prerequisites_beam_tools(Plm_image::Pointer& target)
+Rt_beam::add_spot (
+    float xpos,
+    float ypos,
+    float energy,
+    float sigma,
+    float weight)
 {
-    if (d_ptr->mebs->get_have_particle_number_map() == true && d_ptr->beam_line_type == "passive")
+    d_ptr->spot_map->add_spot (xpos, ypos, energy, sigma, weight);
+}
+
+bool
+Rt_beam::prepare_for_calc (
+    Plm_image::Pointer& ct_hu,
+    Plm_image::Pointer& ct_psp,
+    Plm_image::Pointer& target)
+{
+    if (!ct_hu) return false;
+    if (!ct_psp) return false;
+    d_ptr->ct_hu = ct_hu;
+    d_ptr->ct_psp = ct_psp;
+    d_ptr->target = target;
+
+    if (this->get_aperture()->get_distance() > this->get_source_distance ()) {
+        lprintf ("Source distance must be greater than aperture distance");
+        return false;
+    }
+
+    Rpl_volume_ray_trace_start rvrts = RAY_TRACE_START_AT_CLIPPING_PLANE;
+    
+    // Create rsp_accum_vol */
+    if (!this->rsp_accum_vol) {
+        this->rsp_accum_vol = new Rpl_volume;
+    }
+    if (!this->rsp_accum_vol) return false;
+    this->rsp_accum_vol->set_geometry (
+        this->get_source_position(),
+        this->get_isocenter_position(),
+        this->get_aperture()->vup,
+        this->get_aperture()->get_distance(),
+        this->get_aperture()->get_dim(),
+        this->get_aperture()->get_center(),
+        this->get_aperture()->get_spacing(),
+        this->get_step_length());
+    this->rsp_accum_vol->set_aperture (this->get_aperture());
+    this->rsp_accum_vol->set_ray_trace_start (rvrts);
+    this->rsp_accum_vol->set_ct_volume (ct_psp);
+    if (!this->rsp_accum_vol->get_ct() || !this->rsp_accum_vol->get_ct_limit()) {
+        lprintf ("ray_data or clipping planes missing from rpl volume\n");
+        return false;
+    }
+    this->rsp_accum_vol->compute_rpl_accum (false);
+
+    // Create ct projective volume
+    // GCS FIX: The old code re-used the ray data.  Is that really faster?
+    this->hu_samp_vol = new Rpl_volume;
+    if (!this->hu_samp_vol) return false;
+    this->hu_samp_vol->clone_geometry (this->rsp_accum_vol);
+    this->hu_samp_vol->set_ray_trace_start (rvrts);
+    this->hu_samp_vol->set_aperture (this->get_aperture());
+    this->hu_samp_vol->set_ct_volume (d_ptr->ct_hu);
+    this->hu_samp_vol->compute_rpl_sample (false);
+
+    // Prepare, but don't compute the sigma volume yet
+    if (this->get_flavor() == "d")
     {
-        printf("***WARNING*** Passively scattered beam line with spot map file detected: %s.\nBeam line set to active scanning.\n", d_ptr->mebs->get_particle_number_in().c_str());
-        printf("Any manual peaks set, depth prescription, target or range compensator will not be considered.\n");
-        this->compute_beam_data_from_spot_map();
-        return;
+        this->sigma_vol = new Rpl_volume;
+        if (!this->sigma_vol) return false;
+        this->sigma_vol->clone_geometry (this->rsp_accum_vol);
+        this->sigma_vol->set_aperture (this->get_aperture());
+        this->sigma_vol->set_ct_volume (d_ptr->ct_hu);
+        this->sigma_vol->set_ct_limit(this->rsp_accum_vol->get_ct_limit());
+        this->sigma_vol->compute_ray_data();
+        this->sigma_vol->set_front_clipping_plane(this->rsp_accum_vol->get_front_clipping_plane());
+        this->sigma_vol->set_back_clipping_plane(this->rsp_accum_vol->get_back_clipping_plane());
+        this->sigma_vol->compute_rpl_void();
+    }
+
+    // Create target projective volume */
+    if (d_ptr->target) {
+        this->target_rv = Rpl_volume::New();
+        if (!this->target_rv) return false;
+        this->target_rv->clone_geometry (this->rsp_accum_vol);
+        this->target_rv->set_ray_trace_start (rvrts);
+        this->target_rv->set_aperture (this->get_aperture());
+        this->target_rv->set_ct_volume (d_ptr->target);
+        this->target_rv->compute_rpl_sample (false);
     }
 
-    /* The priority gets to spot map > manual peaks > dose prescription > target */
+    // Create and fill in rpl_dose_volume (actually proj dose)
+    if (this->get_flavor() == "b"
+        || this->get_flavor() == "ray_trace_dij_a"
+        || this->get_flavor() == "ray_trace_dij_b"
+        || this->get_flavor() == "d")
+    {
+        this->dose_rv = new Rpl_volume;
+        if (!this->dose_rv) return false;
+        this->dose_rv->clone_geometry (this->rsp_accum_vol);
+        this->dose_rv->set_ray_trace_start (rvrts);
+        this->dose_rv->set_aperture (this->get_aperture());
+        this->dose_rv->set_ct_volume (d_ptr->ct_hu);
+        this->dose_rv->set_ct_limit(this->rsp_accum_vol->get_ct_limit());
+        this->dose_rv->compute_ray_data();
+        this->dose_rv->set_front_clipping_plane(this->rsp_accum_vol->get_front_clipping_plane());
+        this->dose_rv->set_back_clipping_plane(this->rsp_accum_vol->get_back_clipping_plane());
+        this->dose_rv->compute_rpl_void();
+    }
+
+   /* The priority how to generate dose is:
+       1. manual beamlet map 
+       2. manual spot map
+       3. manual peaks 
+       4. dose prescription 
+       5. target 
+       6. 100 MeV sample beam */
     if (d_ptr->mebs->get_have_particle_number_map() == true)
     {
-        printf("Spot map file detected: Any manual peaks set, depth prescription, target or range compensator will not be considered.\n");
-        this->compute_beam_data_from_spot_map();
-        return;
+        lprintf ("Beamlet map file detected: Any manual peaks set, depth prescription, target or range compensator will not be considered.\n");
+        this->compute_beam_data_from_beamlet_map ();
+        return true;
+    }
+    if (d_ptr->spot_map->num_spots() > 0)
+    {
+        lprintf ("Beam specified by spot map\n");
+        this->get_mebs()->set_have_manual_peaks(false);
+        this->get_mebs()->set_have_prescription(false);
+        this->compute_beam_data_from_spot_map ();
+        return true;
     }
     if (d_ptr->mebs->get_have_manual_peaks() == true)
     {
-        printf("Manual peaks detected [PEAKS]: Any prescription or target depth will not be considered.\n");
-        this->get_mebs()->set_have_manual_peaks(true);
-        this->compute_beam_data_from_manual_peaks(target);
-        return;
+        lprintf("Manual peaks detected [PEAKS]: Any prescription or target depth will not be considered.\n");
+        this->get_mebs()->set_have_manual_peaks (true);
+        this->compute_beam_data_from_manual_peaks (target);
+        return true;
     }
     if (d_ptr->mebs->get_have_prescription() == true)
     {
+        lprintf ("Prescription depths detected. Any target depth will not be considered.\n");
         this->get_mebs()->set_have_prescription(true);
         /* Apply margins */
-        this->get_mebs()->set_target_depths(d_ptr->mebs->get_prescription_min(), d_ptr->mebs->get_prescription_max());
-        printf("Prescription depths detected. Any target depth will not be considered.\n");
-        this->compute_beam_data_from_prescription(target);
-        return;
+        this->get_mebs()->set_target_depths (d_ptr->mebs->get_prescription_min(), d_ptr->mebs->get_prescription_max());
+        this->compute_beam_data_from_prescription (target);
+        return true;
     }
-    if (target->get_vol())
+    if (target && target->get_vol())
     {
-        printf("Target detected.\n");
+        lprintf("Target detected.\n");
         this->get_mebs()->set_have_manual_peaks(false);
         this->get_mebs()->set_have_prescription(false);
         this->compute_beam_data_from_target(target);
-        return;
+        return true;
     }
-	
+
     /* If we arrive to this point, it is because no beam was defined
        Creation of a default beam: 100 MeV */
-    printf("***WARNING*** No spot map, manual peaks, depth prescription or target detected.\n");
-    printf("Beam set to a 100 MeV mono-energetic beam. Proximal and distal margins not considered.\n");
-    this->compute_default_beam();
-    return;
+    lprintf("***WARNING*** No beamlet map, manual peaks, depth prescription or target detected.\n");
+    lprintf("Beam set to a 100 MeV mono-energetic beam. Proximal and distal margins not considered.\n");
+    this->compute_default_beam ();
+
+    return true;
 }
 
 void
-Rt_beam::compute_beam_data_from_spot_map()
+Rt_beam::compute_beam_data_from_beamlet_map()
 {
-    this->get_mebs()->clear_depth_dose();
-    this->get_mebs()->extract_particle_number_map_from_txt(this->get_aperture());
+    this->get_mebs()->clear_depth_dose ();
+    this->get_mebs()->load_beamlet_map (this->get_aperture());
 
-    /* If an aperture is defined in the input file, the aperture is erased. 
-       The range compensator is not considered if the beam line is defined as active scanning */
-    this->update_aperture_and_range_compensator();
+    /* the automatic aperture and range compensator are erased and the 
+       ones defined in the input file are considered */
+    this->update_aperture_and_range_compensator ();
 }
 
 void
-Rt_beam::compute_beam_data_from_manual_peaks(Plm_image::Pointer& target)
+Rt_beam::compute_beam_data_from_spot_map()
 {
-    /* The spot map will be identical for passive or scanning beam lines */
-    int ap_dim[2] = {this->get_aperture()->get_dim()[0], this->get_aperture()->get_dim()[1]};
+    this->get_mebs()->set_from_spot_map (d_ptr->spot_map);
+}
+
+void
+Rt_beam::compute_beam_data_from_manual_peaks (Plm_image::Pointer& target)
+{
+    /* The beamlet map will be identical for passive or scanning beam lines */
+    const plm_long* ap_dim = this->get_aperture()->get_dim();
     this->get_mebs()->generate_part_num_from_weight(ap_dim);
-    if ((target->get_vol() && (d_ptr->aperture_in =="" || d_ptr->range_compensator_in =="")) && (d_ptr->mebs->get_have_manual_peaks() == true || d_ptr->mebs->get_have_prescription() == true)) // we build the associate range compensator and aperture
+    if ((target && (d_ptr->aperture_in =="" || d_ptr->range_compensator_in =="")) && (d_ptr->mebs->get_have_manual_peaks() == true || d_ptr->mebs->get_have_prescription() == true)) // we build the associate range compensator and aperture
     {
         if (d_ptr->beam_line_type == "active")
         {
-            this->rpl_vol->compute_beam_modifiers_active_scanning(target->get_vol(), d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin());
+            this->compute_beam_modifiers_active_scanning (
+                target->get_vol(), d_ptr->smearing, 
+                d_ptr->mebs->get_proximal_margin(), 
+                d_ptr->mebs->get_distal_margin());
         }
         else
         {
-            this->rpl_vol->compute_beam_modifiers_passive_scattering(target->get_vol(), d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin());
+            this->compute_beam_modifiers_passive_scattering (
+                target->get_vol(), d_ptr->smearing, 
+                d_ptr->mebs->get_proximal_margin(), 
+                d_ptr->mebs->get_distal_margin());
         }
     }
-    /* the aperture and range compensator are erased and the ones defined in the input file are considered */
-    this->update_aperture_and_range_compensator();
-}
-
-void
-Rt_beam::compute_beam_data_from_manual_peaks_passive_slicerRt(Plm_image::Pointer& target)
-{
-    /* The spot map will be identical for passive or scanning beam lines */
-    int ap_dim[2] = {this->get_aperture()->get_dim()[0], this->get_aperture()->get_dim()[1]};
-    this->get_mebs()->generate_part_num_from_weight(ap_dim);
-
-    this->rpl_vol->compute_beam_modifiers_passive_scattering_slicerRt(target, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin());
-    
-    /* the aperture and range compensator are erased and the ones defined in the input file are considered */
+    /* the automatic aperture and range compensator are erased and the 
+       ones defined in the input file are considered */
     this->update_aperture_and_range_compensator();
 }
 
 void
 Rt_beam::compute_beam_data_from_manual_peaks()
 {
-    /* The spot map will be identical for passive or scanning beam lines */
-    int ap_dim[2] = {this->get_aperture()->get_dim()[0], this->get_aperture()->get_dim()[1]};
+    /* The beamlet map will be identical for passive or scanning beam lines */
+    const plm_long *ap_dim = this->get_aperture()->get_dim();
     this->get_mebs()->generate_part_num_from_weight(ap_dim);
-    /* the aperture and range compensator are erased and the ones defined in the input file are considered */
+    /* the automatic aperture and range compensator are erased and the 
+       ones defined in the input file are considered */
     this->update_aperture_and_range_compensator();
 }
 
 void
 Rt_beam::compute_beam_data_from_prescription(Plm_image::Pointer& target)
 {
-    /* The spot map will be identical for passive or scanning beam lines */
+    /* The beamlet map will be identical for passive or scanning beam lines */
     /* Identic to compute from manual peaks, with a preliminary optimization */
     d_ptr->mebs->optimize_sobp();
     this->compute_beam_data_from_manual_peaks(target);
@@ -454,24 +607,34 @@ Rt_beam::compute_beam_data_from_target(Plm_image::Pointer& target)
 {
     /* Compute beam aperture, range compensator 
        + SOBP for passively scattered beam lines */
-	
-    if (this->get_beam_line_type() != "passive")
+    if (this->get_beam_line_type() == "passive")
     {
-        d_ptr->mebs->compute_particle_number_matrix_from_target_active(this->rpl_vol, this->get_target(), d_ptr->smearing);
+        this->compute_beam_modifiers (
+            d_ptr->target->get_vol(), this->get_mebs()->get_min_wed_map(),
+            this->get_mebs()->get_max_wed_map());
+        this->compute_beam_data_from_prescription (target);
     }
     else
     {
-        this->compute_beam_modifiers (d_ptr->target->get_vol(), this->get_mebs()->get_min_wed_map(), this->get_mebs()->get_max_wed_map());
-        this->compute_beam_data_from_prescription(target);
+        std::vector <double> wepl_min;
+        std::vector <double> wepl_max;
+        this->compute_beam_modifiers_active_scanning (
+            target->get_vol(), d_ptr->smearing,
+            d_ptr->mebs->get_proximal_margin(),
+            d_ptr->mebs->get_distal_margin(),
+            wepl_min, wepl_max);
+
+        d_ptr->mebs->compute_particle_number_matrix_from_target_active (
+            this->rsp_accum_vol, wepl_min, wepl_max);
     }
 }
 
 void 
 Rt_beam::compute_default_beam()
 {
-	/* Computes a default 100 MeV peak */
-	this->get_mebs()->add_peak(100, 1, 1);
-	this->compute_beam_data_from_manual_peaks();
+    /* Computes a default 100 MeV peak */
+    this->get_mebs()->add_peak (100, 1, 1);
+    this->compute_beam_data_from_manual_peaks ();
 }
 
 void 
@@ -479,16 +642,19 @@ Rt_beam::compute_beam_modifiers (Volume *seg_vol)
 {
     if (d_ptr->beam_line_type == "active")
     {
-        this->rpl_vol->compute_beam_modifiers_active_scanning(seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin());
+        this->compute_beam_modifiers_active_scanning (seg_vol, 
+            d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), 
+            d_ptr->mebs->get_distal_margin());
     }
     else
     {
-        this->rpl_vol->compute_beam_modifiers_passive_scattering(seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin());
+        this->compute_beam_modifiers_passive_scattering (seg_vol, 
+            d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), 
+            d_ptr->mebs->get_distal_margin());
     }
 
-    d_ptr->mebs->set_prescription_depths(this->rpl_vol->get_min_wed(), this->rpl_vol->get_max_wed());
-    this->rpl_vol->apply_beam_modifiers ();
-    return;
+    d_ptr->mebs->set_prescription_depths (d_ptr->min_wed, d_ptr->max_wed);
+    this->rsp_accum_vol->apply_beam_modifiers ();
 }
 
 void 
@@ -496,20 +662,368 @@ Rt_beam::compute_beam_modifiers (Volume *seg_vol, std::vector<double>& map_wed_m
 {
     if (d_ptr->beam_line_type == "active")
     {
-        this->rpl_vol->compute_beam_modifiers_active_scanning(seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin(), map_wed_min, map_wed_max);
+        this->compute_beam_modifiers_active_scanning (
+            seg_vol, d_ptr->smearing,
+            d_ptr->mebs->get_proximal_margin(),
+            d_ptr->mebs->get_distal_margin(), map_wed_min, map_wed_max);
     }
     else
     {
-        this->rpl_vol->compute_beam_modifiers_passive_scattering(seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin(), map_wed_min, map_wed_max);
+        this->compute_beam_modifiers_passive_scattering (seg_vol, 
+            d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), 
+            d_ptr->mebs->get_distal_margin(), map_wed_min, map_wed_max);
+    }
+    d_ptr->mebs->set_prescription_depths (d_ptr->min_wed, d_ptr->max_wed);
+    this->rsp_accum_vol->apply_beam_modifiers ();
+}
+
+void 
+Rt_beam::compute_beam_modifiers_active_scanning (
+    Volume *seg_vol, float smearing, float proximal_margin,
+    float distal_margin)
+{
+    std::vector<double> map_wed_min;
+    std::vector<double> map_wed_max;
+    this->compute_beam_modifiers_core (seg_vol, true, smearing, proximal_margin,
+        distal_margin, map_wed_min, map_wed_max);
+}
+
+void 
+Rt_beam::compute_beam_modifiers_passive_scattering (
+    Volume *seg_vol, float smearing, float proximal_margin, 
+    float distal_margin)
+{
+    std::vector<double> map_wed_min;
+    std::vector<double> map_wed_max;
+    this-> compute_beam_modifiers_core (seg_vol, false, smearing, 
+        proximal_margin, distal_margin, map_wed_min, map_wed_max);
+}
+
+void 
+Rt_beam::compute_beam_modifiers_active_scanning (
+    Volume *seg_vol, float smearing, float proximal_margin,
+    float distal_margin, std::vector<double>& map_wed_min,
+    std::vector<double>& map_wed_max)
+{
+    this->compute_beam_modifiers_core (seg_vol, true, smearing, proximal_margin,
+        distal_margin, map_wed_min, map_wed_max);
+}
+
+void 
+Rt_beam::compute_beam_modifiers_passive_scattering (
+    Volume *seg_vol, float smearing, float proximal_margin, 
+    float distal_margin, std::vector<double>& map_wed_min, 
+    std::vector<double>& map_wed_max)
+{
+    this-> compute_beam_modifiers_core (seg_vol, false, smearing, 
+        proximal_margin, distal_margin, map_wed_min, map_wed_max);
+}
+
+void
+Rt_beam::compute_beam_modifiers_core (
+    Volume *seg_vol,
+    bool active,
+    float smearing,
+    float proximal_margin,
+    float distal_margin,
+    std::vector<double>& map_wed_min,
+    std::vector<double>& map_wed_max)
+{
+    printf("Compute target wepl_min_max...\n");
+    this->compute_target_wepl_min_max (map_wed_min, map_wed_max);
+
+#if defined (commentout)
+    save_vector_as_image (
+        map_wed_min,
+        d_ptr->aperture->get_dim(),
+        "debug-min-a.nrrd");
+    save_vector_as_image (
+        map_wed_max,
+        d_ptr->aperture->get_dim(),
+        "debug-max-a.nrrd");
+#endif
+    
+    printf ("Apply lateral smearing to the target...\n");
+    /* widen the min/max distance maps */
+    if (smearing > 0) {
+        this->apply_smearing_to_target (smearing, map_wed_min, map_wed_max);
+    }
+
+#if defined (commentout)
+    save_vector_as_image (
+        map_wed_min,
+        d_ptr->aperture->get_dim(),
+        "debug-min-b.nrrd");
+    save_vector_as_image (
+        map_wed_max,
+        d_ptr->aperture->get_dim(),
+        "debug-max-b.nrrd");
+#endif
+    
+    printf ("Apply proximal and distal ...\n");
+    /* add the margins */
+    for (size_t i = 0; i < map_wed_min.size(); i++) {
+        map_wed_min[i] -= proximal_margin;
+        if (map_wed_min[i] < 0) {
+            map_wed_min[i] = 0;
+        }
+        if (map_wed_max[i] > 0) {
+            map_wed_max[i] += distal_margin;
+        }
+    }
+
+#if defined (commentout)
+    save_vector_as_image (
+        map_wed_min,
+        d_ptr->aperture->get_dim(),
+        "debug-min-c.nrrd");
+    save_vector_as_image (
+        map_wed_max,
+        d_ptr->aperture->get_dim(),
+        "debug-max-c.nrrd");
+#endif
+    
+    /* Compute max wed, used by range compensator */
+    int idx = 0;
+    double max_wed = 0;
+    int i[2] = {0, 0};
+    printf("Compute max wed...\n");
+    for (i[1] = 0; i[1] < d_ptr->aperture->get_aperture_volume()->dim[1]; i[1]++) {
+        for (i[0] = 0; i[0] < d_ptr->aperture->get_aperture_volume()->dim[0]; i[0]++) {
+            idx = i[0] + i[1] * d_ptr->aperture->get_aperture_volume()->dim[0];
+            if (map_wed_max[idx] > max_wed) {
+                max_wed = map_wed_max[idx];
+            }
+        }
+    }
+
+    printf("Compute the aperture...\n");
+    /* compute the aperture */
+    /* This assumes that dim & spacing are correctly set in aperture */
+    d_ptr->aperture->allocate_aperture_images ();
+
+    Volume::Pointer aperture_vol = d_ptr->aperture->get_aperture_volume ();
+    unsigned char *aperture_img = (unsigned char*) aperture_vol->img;
+    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++) {
+        if (map_wed_min[i] > 0) {
+            aperture_img[i] = 1;
+        }
+        else {
+            aperture_img[i] = 0;
+        }
+    }
+
+    /* compute the range compensator if passive beam line with PMMA 
+       range compensator */
+    Volume::Pointer range_comp_vol = d_ptr->aperture->get_range_compensator_volume ();
+    float *range_comp_img = (float*) range_comp_vol->img;
+	
+    if (active == false)
+    {
+        printf("Compute range compensator...\n");
+    }
+
+    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
+    {
+        if (active == true)
+        {
+            range_comp_img[i] = 0;
+        }
+        else 
+        {
+            range_comp_img[i] = (max_wed - map_wed_max[i]) / (PMMA_STPR * PMMA_DENSITY);
+        }
+    }
+
+    /* compute the max/min wed of the entire target + margins + range_comp*/
+    double total_min_wed = 0;
+    double total_max_wed = 0;
+    // Max should be the same as the max in the target as for this ray rgcomp is null
+    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
+    {
+        if (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > total_max_wed) { // if active beam line, range comp is null
+            total_max_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i];
+        }
+    }
+    total_min_wed = total_max_wed;
+    for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++)
+    {
+        if ((range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > 0) && (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i] < total_min_wed)) {
+            total_min_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i];
+        }
+    }
+
+    printf("Max wed in the target is %lg mm.\n", total_max_wed);
+    printf("Min wed in the target is %lg mm.\n", total_min_wed);
+
+    /* Save these values in private data store */
+    // GCS FIX: To be revisited
+    d_ptr->max_wed = total_max_wed;
+    d_ptr->min_wed = total_min_wed;
+}
+
+void
+Rt_beam::compute_target_wepl_min_max (
+    std::vector<double>& map_wed_min,
+    std::vector<double>& map_wed_max)
+{
+    Rpl_volume *wepl_rv = this->rsp_accum_vol;
+    Volume *wepl_vol = wepl_rv->get_vol ();
+    float *wepl_img = wepl_vol->get_raw<float> ();
+    Rpl_volume::Pointer target_rv = this->target_rv;
+    Volume *target_vol = target_rv->get_vol ();
+    float *target_img = target_vol->get_raw<float> ();
+    const plm_long *target_dim = target_vol->get_dim ();
+    
+    map_wed_min.resize (target_dim[0]*target_dim[1], NLMAX(double));
+    map_wed_max.resize (target_dim[0]*target_dim[1], 0.);
+
+    int ij[2] = {0, 0};
+    int num_steps = this->target_rv->get_num_steps();
+    for (ij[1] = 0; ij[1] < target_dim[1]; ij[1]++) {
+        for (ij[0] = 0; ij[0] < target_dim[0]; ij[0]++) {
+            int map_idx = ij[0] + ij[1] * target_dim[0];
+            for (int s = 0; s < num_steps; s++) {
+                int rv_index = target_vol->index (ij[0],ij[1],s);
+                float tgt = target_img[rv_index];
+                float wepl = wepl_img[rv_index];
+                if (tgt < 0.2) {
+                    continue;
+                }
+                if (map_wed_min[map_idx] > wepl) {
+                    map_wed_min[map_idx] = wepl;
+                }
+                if (map_wed_max[map_idx] < wepl) {
+                    map_wed_max[map_idx] = wepl;
+                }
+            }
+        }
+    }
+}
+
+void 
+Rt_beam::apply_smearing_to_target (
+    float smearing,
+    std::vector <double>& map_min_distance,
+    std::vector <double>& map_max_distance)
+{
+    // GCS FIX.  It appears that the reason for computing geometric
+    // distance in the previous version of the code was to make the
+    // smearing code act at the minimum target distance.  This is unnecessary; 
+    // it is easier/better to apply at isocenter plane.
+
+    // Convert smearing from isocenter to aperture plane
+    const Aperture::Pointer& ap = d_ptr->aperture;
+    float smearing_ap = smearing
+        * ap->get_distance() / this->get_source_distance();
+    printf ("Smearing = %f, Smearing_ap = %f\n", smearing, smearing_ap);
+
+    /* Create a structured element of the right size */
+    int strel_half_size[2];
+    int strel_size[2];
+    strel_half_size[0] = ROUND_INT (smearing_ap / ap->get_spacing()[0]);
+    strel_half_size[1] = ROUND_INT (smearing_ap / ap->get_spacing()[1]);
+    
+    strel_size[0] = 1 + 2 * strel_half_size[0];
+    strel_size[1] = 1 + 2 * strel_half_size[1];
+
+    printf ("Strel size = (%d,%d), (%d,%d)\n", 
+        strel_half_size[0], strel_half_size[1],
+        strel_size[0], strel_size[1]);
+
+    int *strel = new int[strel_size[0]*strel_size[1]];
+    /* (rf, cf) center of the smearing */
+    for (int r = 0; r < strel_size[1]; r++) {
+        float rf = (float) (r - strel_half_size[1]) * ap->get_spacing()[0];
+        for (int c = 0; c < strel_size[0]; c++) {
+            float cf = (float) (c - strel_half_size[0]) * ap->get_spacing()[1];
+
+            int idx = r*strel_size[0] + c;
+
+            strel[idx] = 0;
+            if ((rf*rf + cf*cf) <= smearing_ap*smearing_ap) {
+                strel[idx] = 1;
+            }
+        }
+    }
+
+    /* Debugging information */
+    for (int r = 0; r < strel_size[1]; r++) {
+        for (int c = 0; c < strel_size[0]; c++) {
+            int idx = r*strel_size[0] + c;
+            printf ("%d ", strel[idx]);
+        }
+        printf ("\n");
+    }
+
+    // GCS FIX.  This is also in error.  The smearing should be done 
+    // in WEPL rather than in geometric distance.
+    /* Apply smear to target maps */
+    double distance_min;
+    double distance_max;
+    std::vector<double> min_distance_tmp (map_min_distance.size(), 0);
+    std::vector<double> max_distance_tmp (map_max_distance.size(), 0);
+
+    for (int ar = 0; ar < d_ptr->aperture->get_dim()[1]; ar++) {
+        for (int ac = 0; ac < d_ptr->aperture->get_dim()[0]; ac++) {
+            int aidx = ar * d_ptr->aperture->get_dim()[0] + ac;
+
+            /* Reset the limit values */
+            distance_min = DBL_MAX;
+            distance_max = 0;
+
+            for (int sr = 0; sr < strel_size[1]; sr++) {
+                int pr = ar + sr - strel_half_size[1];
+                if (pr < 0 || pr >= d_ptr->aperture->get_dim()[1]) {
+                    continue;
+                }
+                for (int sc = 0; sc < strel_size[0]; sc++) {
+                    int pc = ac + sc - strel_half_size[0];
+                    if (pc < 0 || pc >= d_ptr->aperture->get_dim()[0]) {
+                        continue;
+                    }
+
+                    int sidx = sr * strel_size[0] + sc;
+                    if (strel[sidx] == 0) {
+                        continue;
+                    }
+
+                    int pidx = pr * d_ptr->aperture->get_dim()[0] + pc;
+                    if (map_min_distance[pidx] > 0 && map_min_distance[pidx] < distance_min) {
+                        distance_min = map_min_distance[pidx];
+                    }
+                    if (map_max_distance[pidx] > distance_max) {
+                        distance_max = map_max_distance[pidx];
+                    }
+                }
+            }
+            if (distance_min == DBL_MAX)
+            {
+                min_distance_tmp[aidx] = 0;
+            }
+            else 
+            {
+                min_distance_tmp[aidx] = distance_min;
+            }
+            max_distance_tmp[aidx] = distance_max;
+        }
+    }
+
+    /* update the initial distance map */
+    for (size_t i = 0; i < map_min_distance.size(); i++) {
+        map_min_distance[i] = min_distance_tmp[i];
+        map_max_distance[i] = max_distance_tmp[i];
     }
-    d_ptr->mebs->set_prescription_depths(this->rpl_vol->get_min_wed(), this->rpl_vol->get_max_wed());
-    this->rpl_vol->apply_beam_modifiers ();
-    return;
+
+    /* Clean up */
+    delete[] strel;
 }
 
 void
-Rt_beam::update_aperture_and_range_compensator()
+Rt_beam::update_aperture_and_range_compensator ()
 {
+    // GCS FIX.  The below logic is no longer valid
+#if defined (commentout)
     /* The aperture is copied from rpl_vol
        the range compensator and/or the aperture are erased if defined in the input file */
     if (d_ptr->aperture_in != "")
@@ -517,7 +1031,7 @@ Rt_beam::update_aperture_and_range_compensator()
         Plm_image::Pointer ap_img = Plm_image::New (d_ptr->aperture_in, PLM_IMG_TYPE_ITK_UCHAR);
         this->get_aperture()->set_aperture_image(d_ptr->aperture_in.c_str());
         this->get_aperture()->set_aperture_volume(ap_img->get_volume_uchar());
-        if (this->rpl_vol->get_minimum_distance_target() == 0) // means that there is no target defined
+        if (this->rsp_accum_vol->get_minimum_distance_target() == 0) // means that there is no target defined
         {
             printf("Smearing applied to the aperture. The smearing width is defined in the aperture frame.\n");
             d_ptr->aperture->apply_smearing_to_aperture(d_ptr->smearing, d_ptr->aperture->get_distance());
@@ -525,7 +1039,7 @@ Rt_beam::update_aperture_and_range_compensator()
         else
         {
             printf("Smearing applied to the aperture. The smearing width is defined at the target minimal distance.\n");
-            d_ptr->aperture->apply_smearing_to_aperture(d_ptr->smearing, this->rpl_vol->get_minimum_distance_target());
+            d_ptr->aperture->apply_smearing_to_aperture(d_ptr->smearing, this->rsp_accum_vol->get_minimum_distance_target());
         }
     }
     /* Set range compensator */
@@ -535,7 +1049,7 @@ Rt_beam::update_aperture_and_range_compensator()
         this->get_aperture()->set_range_compensator_image(d_ptr->range_compensator_in.c_str());
         this->get_aperture()->set_range_compensator_volume(rgc_img->get_volume_float());
 		
-        if (this->rpl_vol->get_minimum_distance_target() == 0) // means that there is no target defined
+        if (this->rsp_accum_vol->get_minimum_distance_target() == 0) // means that there is no target defined
         {
             printf("Smearing applied to the range compensator. The smearing width is defined in the aperture frame.\n");
             d_ptr->aperture->apply_smearing_to_range_compensator(d_ptr->smearing, d_ptr->aperture->get_distance());
@@ -543,9 +1057,28 @@ Rt_beam::update_aperture_and_range_compensator()
         else
         {
             printf("Smearing applied to the range compensator. The smearing width is defined at the target minimal distance.\n");
-            d_ptr->aperture->apply_smearing_to_range_compensator(d_ptr->smearing, this->rpl_vol->get_minimum_distance_target());
+            d_ptr->aperture->apply_smearing_to_range_compensator(d_ptr->smearing, this->rsp_accum_vol->get_minimum_distance_target());
         }
     }
+#endif
+}
+
+Plm_image::Pointer&
+Rt_beam::get_ct_psp ()
+{
+    return d_ptr->ct_psp;
+}
+
+const Plm_image::Pointer&
+Rt_beam::get_ct_psp () const 
+{
+    return d_ptr->ct_psp;
+}
+
+void 
+Rt_beam::set_ct_psp (Plm_image::Pointer& ct_psp)
+{
+    d_ptr->ct_psp = ct_psp;
 }
 
 Plm_image::Pointer&
@@ -561,11 +1094,23 @@ Rt_beam::get_target () const
 }
 
 void 
-Rt_beam::set_target(Plm_image::Pointer& target)
+Rt_beam::set_target (Plm_image::Pointer& target)
 {
     d_ptr->target = target;
 }
 
+void 
+Rt_beam::set_rt_dose_timing (Rt_dose_timing::Pointer& rt_dose_timing)
+{
+    d_ptr->rt_dose_timing = rt_dose_timing;
+}
+
+Rt_dose_timing::Pointer& 
+Rt_beam::get_rt_dose_timing ()
+{
+    return d_ptr->rt_dose_timing;
+}
+
 Plm_image::Pointer&
 Rt_beam::get_dose ()
 {
@@ -596,6 +1141,30 @@ Rt_beam::get_aperture () const
     return d_ptr->aperture;
 }
 
+Plm_image::Pointer&
+Rt_beam::get_aperture_image () 
+{
+    return d_ptr->aperture->get_aperture_image ();
+}
+
+const Plm_image::Pointer&
+Rt_beam::get_aperture_image () const
+{
+    return d_ptr->aperture->get_aperture_image ();
+}
+
+Plm_image::Pointer&
+Rt_beam::get_range_compensator_image () 
+{
+    return d_ptr->aperture->get_range_compensator_image ();
+}
+
+const Plm_image::Pointer&
+Rt_beam::get_range_compensator_image () const
+{
+    return d_ptr->aperture->get_range_compensator_image ();
+}
+
 void
 Rt_beam::set_aperture_vup (const float vup[])
 {
@@ -615,7 +1184,7 @@ Rt_beam::set_aperture_origin (const float ap_origin[])
 }
 
 void
-Rt_beam::set_aperture_resolution (const int ap_resolution[])
+Rt_beam::set_aperture_resolution (const plm_long ap_resolution[])
 {
     this->get_aperture()->set_dim (ap_resolution);
 }
@@ -629,13 +1198,13 @@ Rt_beam::set_aperture_spacing (const float ap_spacing[])
 void 
 Rt_beam::set_step_length(float step)
 {
-	d_ptr->step_length = step;
+    d_ptr->step_length = step;
 }
 
 float 
 Rt_beam::get_step_length()
 {
-	return d_ptr->step_length;
+    return d_ptr->step_length;
 }
 
 void
@@ -735,6 +1304,30 @@ Rt_beam::get_sigma_out()
 }
 
 void 
+Rt_beam::set_beam_dump_out(std::string str)
+{
+    d_ptr->beam_dump_out = str;
+}
+
+std::string 
+Rt_beam::get_beam_dump_out()
+{
+    return d_ptr->beam_dump_out;
+}
+
+void 
+Rt_beam::set_dij_out (const std::string& str)
+{
+    d_ptr->dij_out = str;
+}
+
+const std::string&
+Rt_beam::get_dij_out()
+{
+    return d_ptr->dij_out;
+}
+
+void 
 Rt_beam::set_wed_out(std::string str)
 {
     d_ptr->wed_out = str;
@@ -747,16 +1340,28 @@ Rt_beam::get_wed_out()
 }
 
 void 
+Rt_beam::set_proj_target_out(std::string str)
+{
+    d_ptr->proj_target_out = str;
+}
+
+std::string 
+Rt_beam::get_proj_target_out()
+{
+    return d_ptr->proj_target_out;
+}
+
+void 
 Rt_beam::set_beam_line_type(std::string str)
 {
-	if (str == "active")
-	{
-		d_ptr->beam_line_type = str;
-	}
-	else
-	{
-		d_ptr->beam_line_type = "passive";
-	}
+    if (str == "active")
+    {
+        d_ptr->beam_line_type = str;
+    }
+    else
+    {
+        d_ptr->beam_line_type = "passive";
+    }
 }
 
 std::string
@@ -851,51 +1456,53 @@ Rt_beam::load_txt (const char* fn)
 }
 
 bool
-Rt_beam::get_intersection_with_aperture(double* idx_ap, int* idx, double* rest, double* ct_xyz)
+Rt_beam::get_intersection_with_aperture (
+    double* idx_ap, plm_long* idx, double* rest, double* ct_xyz)
 {
-	double ray[3] = {0,0,0};
-	double length_on_normal_axis = 0;
+    double ray[3] = {0,0,0};
+    double length_on_normal_axis = 0;
 	
-	vec3_copy(ray, ct_xyz);
-	vec3_sub2(ray, d_ptr->source);
+    vec3_copy(ray, ct_xyz);
+    vec3_sub2(ray, d_ptr->source);
 
-	length_on_normal_axis = -vec3_dot(ray, rpl_ct_vol_HU->get_proj_volume()->get_nrm()); // MD Fix: why is the aperture not updated at this point? and why proj vol is?
-	if (length_on_normal_axis < 0)
-	{
-		return false;
-	}
+    length_on_normal_axis = -vec3_dot(ray, hu_samp_vol->get_proj_volume()->get_nrm()); // MD Fix: why is the aperture not updated at this point? and why proj vol is?
+    if (length_on_normal_axis < 0)
+    {
+        return false;
+    }
 
-	vec3_scale2(ray, this->get_aperture()->get_distance()/length_on_normal_axis);
+    vec3_scale2(ray, this->get_aperture()->get_distance()/length_on_normal_axis);
 
-	vec3_add2(ray, d_ptr->source);
-	vec3_sub2(ray, rpl_ct_vol_HU->get_proj_volume()->get_ul_room());
+    vec3_add2(ray, d_ptr->source);
+    vec3_sub2(ray, hu_samp_vol->get_proj_volume()->get_ul_room());
 					
-	idx_ap[0] = vec3_dot(ray, rpl_ct_vol_HU->get_proj_volume()->get_incr_c()) / (this->get_aperture()->get_spacing(0) * this->get_aperture()->get_spacing(0));
-	idx_ap[1] = vec3_dot(ray, rpl_ct_vol_HU->get_proj_volume()->get_incr_r()) / (this->get_aperture()->get_spacing(1) * this->get_aperture()->get_spacing(1));
-	idx[0] = (int) floor(idx_ap[0]);
-	idx[1] = (int) floor(idx_ap[1]);
-	rest[0] = idx_ap[0] - (double) idx[0];
-	rest[1] = idx_ap[1] - (double) idx[1];
-	return true;
+    idx_ap[0] = vec3_dot(ray, hu_samp_vol->get_proj_volume()->get_incr_c()) / (this->get_aperture()->get_spacing(0) * this->get_aperture()->get_spacing(0));
+    idx_ap[1] = vec3_dot(ray, hu_samp_vol->get_proj_volume()->get_incr_r()) / (this->get_aperture()->get_spacing(1) * this->get_aperture()->get_spacing(1));
+    idx[0] = (int) floor(idx_ap[0]);
+    idx[1] = (int) floor(idx_ap[1]);
+    rest[0] = idx_ap[0] - (double) idx[0];
+    rest[1] = idx_ap[1] - (double) idx[1];
+    return true;
 }
 
 bool 
-Rt_beam::is_ray_in_the_aperture(int* idx, unsigned char* ap_img)
-{
-	if ((float) ap_img[idx[0] + idx[1] * this->get_aperture()->get_dim(0)] == 0) {return false;}
-	if (idx[0] + 1 < this->get_aperture()->get_dim(0))
-	{
-		if ((float) ap_img[idx[0] + 1 + idx[1] * this->get_aperture()->get_dim(0)] == 0) {return false;}
-	}
-	if (idx[1] + 1 < this->get_aperture()->get_dim(1))
-	{
-		if ((float) ap_img[idx[0] + (idx[1] + 1) * this->get_aperture()->get_dim(0)] == 0) {return false;}
-	}
-	if (idx[0] + 1 < this->get_aperture()->get_dim(0) && idx[1] + 1 < this->get_aperture()->get_dim(1))
-	{
-		if ((float) ap_img[idx[0] + 1 + (idx[1] + 1) * this->get_aperture()->get_dim(0)] == 0) {return false;}
-	}
-	 return true;
+Rt_beam::is_ray_in_the_aperture (
+    const plm_long* idx, const unsigned char* ap_img)
+{
+    if ((float) ap_img[idx[0] + idx[1] * this->get_aperture()->get_dim(0)] == 0) {return false;}
+    if (idx[0] + 1 < this->get_aperture()->get_dim(0))
+    {
+        if ((float) ap_img[idx[0] + 1 + idx[1] * this->get_aperture()->get_dim(0)] == 0) {return false;}
+    }
+    if (idx[1] + 1 < this->get_aperture()->get_dim(1))
+    {
+        if ((float) ap_img[idx[0] + (idx[1] + 1) * this->get_aperture()->get_dim(0)] == 0) {return false;}
+    }
+    if (idx[0] + 1 < this->get_aperture()->get_dim(0) && idx[1] + 1 < this->get_aperture()->get_dim(1))
+    {
+        if ((float) ap_img[idx[0] + 1 + (idx[1] + 1) * this->get_aperture()->get_dim(0)] == 0) {return false;}
+    }
+    return true;
 }
 
 float 
@@ -968,3 +1575,64 @@ void Rt_beam::set_prescription (float prescription_min, float prescription_max)
 {
     d_ptr->mebs->set_prescription (prescription_min, prescription_max);
 }
+
+void
+Rt_beam::save_beam_output ()
+{
+    /* Save beam modifiers */
+    if (this->get_aperture_out() != "") {
+        Rpl_volume *rpl_vol = this->rsp_accum_vol;
+        Plm_image::Pointer& ap = rpl_vol->get_aperture()->get_aperture_image();
+        ap->save_image (this->get_aperture_out().c_str());
+    }
+
+    if (this->get_range_compensator_out() != ""
+        && this->get_beam_line_type() == "passive")
+    {
+        Rpl_volume *rpl_vol = this->rsp_accum_vol;
+        Plm_image::Pointer& rc = rpl_vol->get_aperture()->get_range_compensator_image();
+        rc->save_image (this->get_range_compensator_out().c_str());
+    }
+
+    /* Save projected density volume */
+    if (d_ptr->proj_img_out != "") {
+        Rpl_volume* proj_img = this->hu_samp_vol;
+        if (proj_img) {
+            proj_img->save (d_ptr->proj_img_out);
+        }
+    }
+
+    /* Save projected dose volume */
+    if (this->get_proj_dose_out() != "") {
+        Rpl_volume* dose_rv = this->dose_rv;
+        if (dose_rv) {
+            dose_rv->save (this->get_proj_dose_out());
+        }
+    }
+
+    /* Save wed volume */
+    if (this->get_wed_out() != "") {
+        Rpl_volume* rpl_vol = this->rsp_accum_vol;
+        if (rpl_vol) {
+            rpl_vol->save (this->get_wed_out());
+        }
+    }
+
+    /* Save projected target volume */
+    if (this->get_proj_target_out() != "") {
+        Rpl_volume::Pointer rpl_vol = this->target_rv;
+        if (rpl_vol) {
+            rpl_vol->save (this->get_proj_target_out());
+        }
+    }
+
+    /* Save the beamlet map */
+    if (this->get_mebs()->get_particle_number_out() != "") {
+        this->get_mebs()->export_as_txt (this->get_aperture());
+    }
+
+    /* Dump beam information */
+    if (this->get_beam_dump_out() != "") {
+        this->dump (this->get_beam_dump_out());
+    }
+}
diff --git a/src/plastimatch/dose/rt_beam.h b/src/plastimatch/dose/rt_beam.h
old mode 100644
new mode 100755
index d4ec0a5..f6d1a43
--- a/src/plastimatch/dose/rt_beam.h
+++ b/src/plastimatch/dose/rt_beam.h
@@ -12,6 +12,7 @@
 #include "aperture.h"
 #include "particle_type.h"
 #include "rpl_volume.h"
+#include "rt_dose_timing.h"
 #include "rt_mebs.h"
 #include "smart_pointer.h"
 
@@ -60,9 +61,9 @@ public:
     double get_source_distance () const;
     
     /*! \brief Get "flavor" parameter of dose calculation algorithm */
-    char get_flavor () const;
+    const std::string& get_flavor () const;
     /*! \brief Set "flavor" parameter of dose calculation algorithm */
-    void set_flavor (char flavor);
+    void set_flavor (const std::string& flavor);
 
     /*! \brief Get "homo_approx" parameter of dose calculation algorithm */
     char get_homo_approx () const;
@@ -92,44 +93,97 @@ public:
     void set_debug (const std::string& dir);
 
     /*! \name Outputs */
-    void dump (const char* dir);     /* Print debugging information */
+    void dump (const char* dir);
+    void dump (const std::string& dir);
+
+    /* Spot scanning */
+    void add_spot (
+        float xpos, float ypos, float energy, float sigma, float weight);
 
     /* Compute beam modifiers, SOBP etc. according to the teatment strategy */
-    void compute_prerequisites_beam_tools(Plm_image::Pointer& target);
+    bool prepare_for_calc (
+        Plm_image::Pointer& ct_hu,
+        Plm_image::Pointer& ct_psp,
+        Plm_image::Pointer& target);
 
     /* Different strategies preparation */
+    void compute_beam_data_from_beamlet_map();
     void compute_beam_data_from_spot_map();
     void compute_beam_data_from_manual_peaks();
     void compute_beam_data_from_manual_peaks(Plm_image::Pointer& target);
-    void compute_beam_data_from_manual_peaks_passive_slicerRt(Plm_image::Pointer& target);
     void compute_beam_data_from_prescription(Plm_image::Pointer& target);
     void compute_beam_data_from_target(Plm_image::Pointer& target);
     void compute_default_beam();
 
     /* This computes the aperture and range compensator */
     void compute_beam_modifiers (Volume *seg_vol);
-    void compute_beam_modifiers (Volume *seg_vol, std::vector<double>& map_wed_min, std::vector<double>& map_wed_max); // returns also the wed max and min maps
-
-    /* copy the aperture and range compensator from the rpl_vol if not defined in the input file */
+    void compute_beam_modifiers (Volume *seg_vol,
+        std::vector<double>& map_wed_min,
+        std::vector<double>& map_wed_max);
+    void compute_beam_modifiers_active_scanning (
+        Volume *seg_vol, float smearing, float proximal_margin,
+        float distal_margin);
+    void compute_beam_modifiers_passive_scattering (
+        Volume *seg_vol, float smearing, float proximal_margin, 
+        float distal_margin);
+    void compute_beam_modifiers_active_scanning (
+        Volume *seg_vol, float smearing, float proximal_margin,
+        float distal_margin, std::vector<double>& map_wed_min,
+        std::vector<double>& map_wed_max);
+    void compute_beam_modifiers_passive_scattering (
+        Volume *seg_vol, float smearing, float proximal_margin, 
+        float distal_margin, std::vector<double>& map_wed_min, 
+        std::vector<double>& map_wed_max);
+    void compute_beam_modifiers_core (
+        Volume *seg_vol,
+        bool active,
+        float smearing,
+        float proximal_margin,
+        float distal_margin,
+        std::vector<double>& map_wed_min,
+        std::vector<double>& map_wed_max);
+    void apply_smearing_to_target (
+        float smearing,
+        std::vector <double>& map_min_distance,
+        std::vector <double>& map_max_distance);
+    void compute_target_wepl_min_max (
+        std::vector<double>& map_wed_min,
+        std::vector<double>& map_wed_max);
+
+    /* copy the aperture and range compensator from the rpl_vol if not 
+       defined in the input file */
     void update_aperture_and_range_compensator();
 
+    /* Set/ Get ct_psp */
+    Plm_image::Pointer& get_ct_psp ();
+    const Plm_image::Pointer& get_ct_psp () const;
+    void set_ct_psp(Plm_image::Pointer& ct_psp);
+
     /* Set/ Get target */
     Plm_image::Pointer& get_target ();
     const Plm_image::Pointer& get_target () const;
     void set_target(Plm_image::Pointer& target);
 
+    /* Set/ Get timer */
+    Rt_dose_timing::Pointer& get_rt_dose_timing ();
+    void set_rt_dose_timing (Rt_dose_timing::Pointer& rt_dose_timing);
+
     /* Set/ Get dose_volume*/
     Plm_image::Pointer& get_dose ();
     const Plm_image::Pointer& get_dose () const;
     void set_dose(Plm_image::Pointer& dose);
 
-    /* Get aperture */
+    /* Get aperture and range compensator */
     Aperture::Pointer& get_aperture ();
     const Aperture::Pointer& get_aperture () const;
+    Plm_image::Pointer& get_aperture_image ();
+    const Plm_image::Pointer& get_aperture_image () const;
+    Plm_image::Pointer& get_range_compensator_image ();
+    const Plm_image::Pointer& get_range_compensator_image () const;
     void set_aperture_vup (const float[]);
     void set_aperture_distance (float);
     void set_aperture_origin (const float[]);
-    void set_aperture_resolution (const int[]);
+    void set_aperture_resolution (const plm_long[]);
     void set_aperture_spacing (const float[]);
 
     void set_step_length(float step);
@@ -162,14 +216,25 @@ public:
     void set_sigma_out(std::string str);
     std::string get_sigma_out();
 
+    void set_beam_dump_out(std::string str);
+    std::string get_beam_dump_out();
+
+    void set_dij_out (const std::string& str);
+    const std::string& get_dij_out();
+
     void set_wed_out(std::string str);
     std::string get_wed_out();
 
+    void set_proj_target_out(std::string str);
+    std::string get_proj_target_out();
+
     void set_beam_line_type(std::string str);
     std::string get_beam_line_type();
 
-    bool get_intersection_with_aperture(double* idx_ap, int* idx, double* rest, double* ct_xyz);
-    bool is_ray_in_the_aperture(int* idx, unsigned char* ap_img);
+    bool get_intersection_with_aperture (
+        double* idx_ap, plm_long* idx, double* rest, double* ct_xyz);
+    bool is_ray_in_the_aperture (
+        const plm_long* idx, const unsigned char* ap_img);
 
     /* computes the minimal geometric distance of the target for this beam
        -- used for smearing */
@@ -183,21 +248,30 @@ public:
     void set_distal_margin (float distal_margin);
     float get_distal_margin() const;
     void set_prescription (float prescription_min, float prescription_max);
+
+    /* Save beam-specific output files to disk */
+    void save_beam_output ();
     
 public: 
 
-    /* Volumes useful for dose calculation */
-    /* raw volume */
-    Rpl_volume* rpl_vol; // contains the radiologic path length along a ray
-    Rpl_volume* rpl_ct_vol_HU; // contains the HU units along the ray
-    Rpl_volume* sigma_vol;  // contains the sigma (lateral spread of the pencil beam - used to calculate the off-axis term) along the ray
+    /*** Volumes useful for dose calculation */
+    /* contains the target */
+    Rpl_volume::Pointer target_rv;
+    /* contains the radiologic path length along a ray, according to 
+       stopping power */
+    Rpl_volume* rsp_accum_vol;
+    /* contains HU, sampled at each point on the ray */
+    Rpl_volume* hu_samp_vol;
+    // contains the sigma (lateral spread of the pencil beam, 
+    // used to calculate the off-axis term) along the ray 
+    Rpl_volume* sigma_vol;
 
     /* larger volumes for Hong and divergent geometry algorithms */
     Rpl_volume* rpl_vol_lg;
-    Rpl_volume* rpl_ct_vol_HU_lg;
+    Rpl_volume* rpl_vol_samp_lg;
     Rpl_volume* sigma_vol_lg;
-    Rpl_volume* rpl_dose_vol; // contains the dose vol for the divergent geometry algorithm
-    
+    Rpl_volume* dose_rv;
+
 private:
     bool load_xio (const char* fn);
     bool load_txt (const char* fn);
diff --git a/src/plastimatch/util/gabor.h b/src/plastimatch/dose/rt_beam_model.cxx
similarity index 50%
copy from src/plastimatch/util/gabor.h
copy to src/plastimatch/dose/rt_beam_model.cxx
index c4ef841..6beb514 100755
--- a/src/plastimatch/util/gabor.h
+++ b/src/plastimatch/dose/rt_beam_model.cxx
@@ -1,24 +1,21 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _gabor_h_
-#define _gabor_h_
+#include "plmdose_config.h"
 
-#include "plmutil_config.h"
-#include "plm_image.h"
-
-class Gabor_private;
-
-class Gabor 
-{
-public:
-    Gabor_private *d_ptr;
-public:
-    Gabor ();
-    ~Gabor ();
+#include "rt_beam_model.h"
 
+class Rt_beam_model_private {
 public:
-    Plm_image::Pointer get_filter ();
+    int i;
 };
 
-#endif
+Rt_beam_model::Rt_beam_model ()
+{
+    d_ptr = new Rt_beam_model_private;
+}
+
+Rt_beam_model::~Rt_beam_model ()
+{
+    delete d_ptr;
+}
diff --git a/src/plastimatch/dose/rt_beam_model.h b/src/plastimatch/dose/rt_beam_model.h
new file mode 100755
index 0000000..0003a15
--- /dev/null
+++ b/src/plastimatch/dose/rt_beam_model.h
@@ -0,0 +1,21 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _rt_beam_model_h_
+#define _rt_beam_model_h_
+
+#include "plmdose_config.h"
+#include "smart_pointer.h"
+
+class Rt_beam_model_private;
+
+class PLMDOSE_API Rt_beam_model {
+public:
+    SMART_POINTER_SUPPORT (Rt_beam_model);
+    Rt_beam_model_private *d_ptr;
+public:
+    Rt_beam_model ();
+    ~Rt_beam_model ();
+};
+
+#endif
diff --git a/src/plastimatch/dose/rt_depth_dose.cxx b/src/plastimatch/dose/rt_depth_dose.cxx
index 8149bb2..89674f0 100644
--- a/src/plastimatch/dose/rt_depth_dose.cxx
+++ b/src/plastimatch/dose/rt_depth_dose.cxx
@@ -30,7 +30,7 @@ Rt_depth_dose::Rt_depth_dose (
 {
     this->d_lut = NULL;
     this->e_lut = NULL;
-	this->f_lut = NULL;
+    this->f_lut = NULL;
 
     this->E0 = E0;
     this->spread = spread;
@@ -46,9 +46,9 @@ Rt_depth_dose::~Rt_depth_dose ()
     if (this->e_lut) {
         free (this->e_lut);
     }
-	if (this->f_lut) {
-		free (this->f_lut);
-	}
+    if (this->f_lut) {
+        free (this->f_lut);
+    }
 }
 
 bool
@@ -92,11 +92,11 @@ Rt_depth_dose::load_xio (const char* fn)
 
     this->d_lut = (float*)malloc (this->num_samples*sizeof(float));
     this->e_lut = (float*)malloc (this->num_samples*sizeof(float));
-	this->f_lut = (float*)malloc (this->num_samples*sizeof(float));
+    this->f_lut = (float*)malloc (this->num_samples*sizeof(float));
     
     memset (this->d_lut, 0, this->num_samples*sizeof(float));
     memset (this->e_lut, 0, this->num_samples*sizeof(float));
-	memset (this->f_lut, 0, this->num_samples*sizeof(float));
+    memset (this->f_lut, 0, this->num_samples*sizeof(float));
 
     /* load in the depths (10 samples per line) */
     for (i=0, j=0; i<(this->num_samples/10)+1; i++) {
@@ -120,7 +120,7 @@ Rt_depth_dose::load_xio (const char* fn)
         }
     }
 
-	/* load in the energies (10 samples per line) */
+    /* load in the energies (10 samples per line) */
     for (i=0, j=0; i<(this->num_samples/10)+1; i++) {
         fgets (linebuf, 128, fp);
         ptoken = strtok (linebuf, ",\n\0");
@@ -143,28 +143,28 @@ Rt_depth_dose::load_txt (const char* fn)
 
     while (fgets (linebuf, 128, fp)) {
         float range, dose;
-				float dose_int =0;
+        float dose_int =0;
 
         if (2 != sscanf (linebuf, "%f %f", &range, &dose)) {
             break;
         }
 
-				dose_int += dose;
+        dose_int += dose;
         this->num_samples++;
         this->d_lut = (float*) realloc (
-                        this->d_lut,
-                        this->num_samples * sizeof(float));
+            this->d_lut,
+            this->num_samples * sizeof(float));
 
         this->e_lut = (float*) realloc (
-                        this->e_lut,
-                        this->num_samples * sizeof(float));
-				this->f_lut = (float*) realloc (
-						this->f_lut,
-						this->num_samples * sizeof(float));
+            this->e_lut,
+            this->num_samples * sizeof(float));
+        this->f_lut = (float*) realloc (
+            this->f_lut,
+            this->num_samples * sizeof(float));
 
         this->d_lut[this->num_samples-1] = range;
         this->e_lut[this->num_samples-1] = dose;
-				this->f_lut[this->num_samples-1] = dose_int;
+        this->f_lut[this->num_samples-1] = dose_int;
         this->dend = range;         /* Assume entries are sorted */
     }
     fclose (fp);
@@ -177,17 +177,17 @@ Rt_depth_dose::generate ()
     int i;
     double d;
 
-	float max_prep = -1;
-	float depth = -1;
-  if (this->E0 > 190) {depth = 240;} // To accelerate the process and avoid the region where the dose decreases in the first mm (mathematic model) when E>190...
-	float bragg = 0;
-	while (bragg > max_prep)
-	{
-		max_prep = bragg;
-		depth++;
-		bragg = bragg_curve(this->E0, this->spread, depth);
-	}
-	this->dend = depth + 20; // 2 cm margins after the Bragg peak
+    float max_prep = -1;
+    float depth = -1;
+    if (this->E0 > 190) {depth = 240;} // To accelerate the process and avoid the region where the dose decreases in the first mm (mathematic model) when E>190...
+    float bragg = 0;
+    while (bragg > max_prep)
+    {
+        max_prep = bragg;
+        depth++;
+        bragg = bragg_curve(this->E0, this->spread, depth);
+    }
+    this->dend = depth + 20; // 2 cm margins after the Bragg peak
 
 #if SPECFUN_FOUND
     if (!this->E0) {
@@ -205,46 +205,46 @@ Rt_depth_dose::generate ()
     this->num_samples = (int) ceilf (this->dend / this->dres)+1;
     this->d_lut = (float*) malloc (this->num_samples*sizeof(float));
     this->e_lut = (float*) malloc (this->num_samples*sizeof(float));
-	this->f_lut = (float*) malloc (this->num_samples*sizeof(float));
+    this->f_lut = (float*) malloc (this->num_samples*sizeof(float));
     
     memset (this->d_lut, 0, this->num_samples*sizeof(float));
     memset (this->e_lut, 0, this->num_samples*sizeof(float));
-	memset (this->f_lut, 0, this->num_samples*sizeof(float));
+    memset (this->f_lut, 0, this->num_samples*sizeof(float));
 
     for (d=0, i=0; i<this->num_samples; d+=this->dres, i++) {
         d_lut[i] = d;
-		e_lut[i] = bragg_curve (this->E0, this->spread, d);
+        e_lut[i] = bragg_curve (this->E0, this->spread, d);
     }
-	float max = 0;
-	if (this->num_samples > 0) 
-	{ 
-		max = e_lut[0];
-		for (int k = 1; k < this->num_samples; k++)
-		{
-			if (e_lut[k] > max)
-			{
-				max = e_lut[k];
-				this->index_of_dose_max = k;
-			}
-		}
+    float max = 0;
+    if (this->num_samples > 0) 
+    { 
+        max = e_lut[0];
+        for (int k = 1; k < this->num_samples; k++)
+        {
+            if (e_lut[k] > max)
+            {
+                max = e_lut[k];
+                this->index_of_dose_max = k;
+            }
+        }
 	
-		/* normalization and creation of the accumulated dose curve */
-		if (max > 0)
-		{
-			e_lut[0] /= max;
-			f_lut[0] = e_lut[0] * this->dres;
-			for (int k = 1; k < this->num_samples; k++)
-			{
-				e_lut[k] /= max;
-				f_lut[k] = f_lut[k-1] + e_lut[k]*this->dres;
-			}
-		}
-		else
-		{
-			printf("Error: Depth dose curve must have at least one value > 0.\n");
-			return false;
-		}
-	}
+        /* normalization and creation of the accumulated dose curve */
+        if (max > 0)
+        {
+            e_lut[0] /= max;
+            f_lut[0] = e_lut[0] * this->dres;
+            for (int k = 1; k < this->num_samples; k++)
+            {
+                e_lut[k] /= max;
+                f_lut[k] = f_lut[k-1] + e_lut[k]*this->dres;
+            }
+        }
+        else
+        {
+            printf("Error: Depth dose curve must have at least one value > 0.\n");
+            return false;
+        }
+    }
 
     return true;
 #else
@@ -267,41 +267,40 @@ Rt_depth_dose::dump (const char* fn) const
 int 
 Rt_depth_dose::get_index_of_dose_max()
 {
-	return index_of_dose_max;
+    return index_of_dose_max;
 }
 
 float
 Rt_depth_dose::lookup_energy_integration (float depth, float dz) const
 {
-	int i = 0;
-	int j = 0;
+    int i = 0;
+    int j = 0;
 
     float energy = 0.0f;
-	float dres = this->dres;
-	float dmin = depth - dz/2.0;
-	float dmax = depth + dz/2.0;
+    float dmin = depth - dz/2.0;
+    float dmax = depth + dz/2.0;
 
     /* Sanity check */
-	if (depth + dz/2.0 < 0) {
-		return 0.0f;
-	}
+    if (depth + dz/2.0 < 0) {
+        return 0.0f;
+    }
 
     /* Find index into profile arrays */
     for (i = 0; i < this->num_samples-1; i++) {
         if (this->d_lut[i]> dmin) {
-			i--;
+            i--;
             break;
         }
     }
 
-	for (j = i; j < this->num_samples; j++) {
-		if (this->d_lut[j] > dmax) {
-			j--;
-			break;
-		}
-	}
+    for (j = i; j < this->num_samples; j++) {
+        if (this->d_lut[j] > dmax) {
+            j--;
+            break;
+        }
+    }
 
-	/* Use index to lookup and interpolate energy */
+    /* Use index to lookup and interpolate energy */
     if (j >= 0 && j < this->num_samples-1) {
         // linear interpolation
         energy = this->f_lut[j]
@@ -309,28 +308,27 @@ Rt_depth_dose::lookup_energy_integration (float depth, float dz) const
             * ((this->f_lut[j+1] - this->f_lut[j]) 
                 / (this->d_lut[j+1] - this->d_lut[j]));
     } 
-	else
-	{
-		energy = this->f_lut[num_samples-1];
-	}
+    else
+    {
+        energy = this->f_lut[num_samples-1];
+    }
 
-	if (i >= 0 && i < this->num_samples-1) {
-		// linear interpolation
+    if (i >= 0 && i < this->num_samples-1) {
+        // linear interpolation
         energy -= this->f_lut[i]
             + (dmin - this->d_lut[i])
             * ((this->f_lut[i+1] - this->f_lut[i]) 
                 / (this->d_lut[i+1] - this->d_lut[i]));
     } 
-	else if (i == num_samples-1)
-	{
-		energy -= this->f_lut[num_samples-1];
-	}
-	return energy;
+    else if (i == num_samples-1)
+    {
+        energy -= this->f_lut[num_samples-1];
+    }
+    return energy;
 }
 
 float
-Rt_depth_dose::lookup_energy (
-    float depth)
+Rt_depth_dose::lookup_energy (float depth) const
 {	
     int i = 0;
     float energy = 0.0f;
@@ -365,4 +363,4 @@ Rt_depth_dose::lookup_energy (
         energy = 0.0f;
     }
     return energy;
-}
\ No newline at end of file
+}
diff --git a/src/plastimatch/dose/rt_depth_dose.h b/src/plastimatch/dose/rt_depth_dose.h
old mode 100644
new mode 100755
index 78f7c50..83fc9fd
--- a/src/plastimatch/dose/rt_depth_dose.h
+++ b/src/plastimatch/dose/rt_depth_dose.h
@@ -19,28 +19,28 @@ public:
     /* debug: print bragg curve to file */
     void dump (const char* fn) const;
 
-	/* Get dose maximum information */
-	int get_index_of_dose_max();
+    /* Get dose maximum information */
+    int get_index_of_dose_max();
 
-	float lookup_energy_integration(float depth, float dz) const;
-	float lookup_energy (float depth);
+    float lookup_energy_integration(float depth, float dz) const;
+    float lookup_energy (float depth) const;
 
 private:
     bool load_xio (const char* fn);
     bool load_txt (const char* fn);
 
 public:
-    float* d_lut;                   /* depth array (mm) */
-    float* e_lut;                   /* energy array (MeV) */
-	float* f_lut;					/* integrated energy array (MeV) */
+    float* d_lut;                  /* depth array (mm) */
+    float* e_lut;                  /* energy array (MeV) */
+    float* f_lut;                  /* integrated energy array (MeV) */
 
     float E0;                      /* initial ion energy (MeV) */
-    double spread;                  /* beam energy sigma (MeV) */
-    double dres;                    /* spatial resolution of bragg curve (mm)*/
-    double dend;                    /* maximum w.e.d. (mm) */
-    int num_samples;                /* # of discrete bragg curve samples */
+    double spread;                 /* beam energy sigma (MeV) */
+    double dres;                   /* spatial resolution of bragg curve (mm)*/
+    double dend;                   /* maximum w.e.d. (mm) */
+    int num_samples;               /* # of discrete bragg curve samples */
 
-	int index_of_dose_max;
+    int index_of_dose_max;
 };
 
 #endif
diff --git a/src/plastimatch/dose/rt_dij.cxx b/src/plastimatch/dose/rt_dij.cxx
new file mode 100755
index 0000000..3be2dfe
--- /dev/null
+++ b/src/plastimatch/dose/rt_dij.cxx
@@ -0,0 +1,57 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmdose_config.h"
+#include <list>
+
+#include "file_util.h"
+#include "string_util.h"
+#include "rpl_volume.h"
+#include "rt_dij.h"
+#include "volume_macros.h"
+
+void 
+Rt_dij::set_from_dose_rv (
+    const plm_long ij[2],
+    size_t energy_index,
+    const Rpl_volume *dose_rv, 
+    const Volume::Pointer& dose_vol)
+{
+    this->rows.push_back (Rt_dij_row (
+            float (ij[0]), float (ij[1]), float (energy_index)));
+    Rt_dij_row& rt_dij_row = this->rows.back ();
+
+    const Volume *dose = dose_vol.get();
+    plm_long ijk[3];
+    double xyz[3];
+    LOOP_Z (ijk, xyz, dose) {
+        LOOP_Y (ijk, xyz, dose) {
+            LOOP_X (ijk, xyz, dose) {
+                plm_long idx = dose->index (ijk);
+                float val = dose_rv->get_value (xyz);
+                if (val > 0.f) {
+                    rt_dij_row.dose.push_back (Rt_dij_dose (idx, val));
+                }
+            }
+        }
+    }
+}
+
+void 
+Rt_dij::dump (const std::string& dir) const
+{
+    int i = 0;
+    std::list<Rt_dij_row>::const_iterator r = rows.begin();
+    while (r != rows.end()) {
+        std::string fn = string_format ("%s/dij_%04d.txt", dir.c_str(), i++);
+        FILE *fp = plm_fopen (fn, "w");
+        fprintf (fp, "%f %f %f\n", r->xpos, r->ypos, r->energy);
+        std::list<Rt_dij_dose>::const_iterator c = r->dose.begin();
+        while (c != r->dose.end()) {
+            fprintf (fp, "%d %f\n", c->index, c->dose);
+            c++;
+        }
+        fclose (fp);
+        ++r;
+    }
+}
diff --git a/src/plastimatch/dose/rt_dij.h b/src/plastimatch/dose/rt_dij.h
new file mode 100755
index 0000000..97184fb
--- /dev/null
+++ b/src/plastimatch/dose/rt_dij.h
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _rt_dij_h_
+#define _rt_dij_h_
+
+#include "plmdose_config.h"
+#include "smart_pointer.h"
+#include "volume.h"
+
+class Rpl_volume;
+class Rt_dij_private;
+
+class PLMDOSE_API Rt_dij_dose {
+public:
+    Rt_dij_dose (size_t index, float dose) : index(index), dose(dose) 
+    {}
+public:
+    size_t index;
+    float dose;
+};
+
+class PLMDOSE_API Rt_dij_row {
+public:
+    Rt_dij_row (
+        float xpos, float ypos, float energy)
+        : xpos(xpos), ypos(ypos), energy(energy)
+    {}
+public:
+    float xpos;
+    float ypos;
+    float energy;
+    std::list<Rt_dij_dose> dose;
+};
+
+class PLMDOSE_API Rt_dij {
+public:
+    std::list<Rt_dij_row> rows;
+public:
+    void set_from_dose_rv (
+        const plm_long ij[2],
+        size_t energy_index,
+        const Rpl_volume *dose_rv, 
+        const Volume::Pointer& dose_vol);
+    void dump (const std::string& dir) const;
+};
+
+#endif
diff --git a/src/plastimatch/dose/rt_dose.cxx b/src/plastimatch/dose/rt_dose.cxx
old mode 100644
new mode 100755
index 2272fd2..3225893
--- a/src/plastimatch/dose/rt_dose.cxx
+++ b/src/plastimatch/dose/rt_dose.cxx
@@ -17,91 +17,25 @@
 #include "ray_data.h"
 #include "ray_trace.h"
 #include "rpl_volume.h"
+#include "rpl_volume_lut.h"
 #include "rt_beam.h"
 #include "rt_depth_dose.h"
+#include "rt_dij.h"
 #include "rt_dose.h"
 #include "rt_lut.h"
-#include "rt_parms.h"
-#include "rt_plan.h"
 #include "rt_mebs.h"
+#include "rt_plan.h"
+#include "rt_sigma.h"
+#include "string_util.h"
 #include "threading.h"
 #include "volume.h"
 
-#define VERBOSE 1
-#define PROGRESS 1
-//#define DEBUG_VOXEL 1
-//#define DOSE_GAUSS 1
-
-#if defined (commentout)
-static bool voxel_debug = false;
-#endif
-
-/* This function is used to rotate a point about a ray in an orbit
- * perpendicular to the ray.  It is assumed that the arbitrary axis of
- * rotation (ray) originates at the Cartesian origin.
- */
-static void
-rotate_about_ray (
-    double *xyz_new,    /* rotated point */
-    double *xyz,        /* point to rotate */
-    double t,           /* angle of rotation */
-    double *ray         /* axis of rotation */
-)
-{
-    double u[3];
-    double v[3];
-    double w[3];
-    double tmp[3] = {0.0, 0.0, 1.0};
-    double M[12];
-
-#if defined (commentout)
-    double M[16];
-#endif
-
-    /* Generate coordinate system */
-    vec3_copy (w, ray);
-    vec3_normalize1 (w);
-    vec3_cross (v, w, tmp);
-    vec3_normalize1 (v);
-    vec3_cross (u, v, w);
-
-    /* Build the composite matrix
-     *   -- Axis rotation: W coincident Z
-     *   -- Rotates about Z by theta radians
-     *   -- Undoes axis rotation (Z -> W)
-     */
-    M[4*0 + 0] = u[0]*u[0]*cos(t) + u[0]*v[0]*sin(t) - u[0]*v[0]*sin(t) + v[0]*v[0]*cos(t) + w[0]*w[0];
-    M[4*0 + 1] = u[0]*u[1]*cos(t) + u[0]*v[1]*sin(t) - u[1]*v[0]*sin(t) + v[0]*v[1]*cos(t) + w[0]*w[1];
-    M[4*0 + 2] = u[0]*u[2]*cos(t) + u[0]*v[2]*sin(t) - u[2]*v[0]*sin(t) + v[0]*v[2]*cos(t) + w[0]*w[2];
-    M[4*0 + 3] = 0;
-
-    M[4*1 + 0] = u[1]*u[0]*cos(t) + u[1]*v[0]*sin(t) - u[0]*v[1]*sin(t) + v[1]*v[0]*cos(t) + w[1]*w[0];
-    M[4*1 + 1] = u[1]*u[1]*cos(t) + u[1]*v[1]*sin(t) - u[1]*v[1]*sin(t) + v[1]*v[1]*cos(t) + w[1]*w[1]; 
-    M[4*1 + 2] = u[1]*u[2]*cos(t) + u[1]*v[2]*sin(t) - u[2]*v[1]*sin(t) + v[1]*v[2]*cos(t) + w[1]*w[2]; 
-    M[4*1 + 3] = 0;
-
-    M[4*2 + 0] = u[2]*u[0]*cos(t) + u[2]*v[0]*sin(t) - u[0]*v[2]*sin(t) + v[2]*v[0]*cos(t) + w[2]*w[0];
-    M[4*2 + 1] = u[2]*u[1]*cos(t) + u[2]*v[1]*sin(t) - u[1]*v[2]*sin(t) + v[2]*v[1]*cos(t) + w[2]*w[1];
-    M[4*2 + 2] = u[2]*u[2]*cos(t) + u[2]*v[2]*sin(t) - u[2]*v[2]*sin(t) + v[2]*v[2]*cos(t) + w[2]*w[2];
-    M[4*2 + 3] = 0;
-
-#if defined (commentout)
-    M[4*3 + 0] = 0;
-    M[4*3 + 1] = 0;
-    M[4*3 + 2] = 0;
-    M[4*3 + 3] = 1;
-#endif
-
-    /* Apply rotation transform */
-    mat43_mult_vec3(xyz_new, M, xyz);
-}
-
 /* Ray Tracer */
 double
 energy_direct (
     float rgdepth,          /* voxel to dose */
-	Rt_beam* beam,
-	int beam_idx
+    Rt_beam* beam,
+    int beam_idx
 )
 {
     /* The voxel was not hit directly by the beam */
@@ -110,611 +44,500 @@ energy_direct (
     }
 
     /* return the dose at this radiographic depth */
-	return (double) beam->get_mebs()->get_depth_dose()[beam_idx]->lookup_energy(rgdepth);
+    return (double) beam->get_mebs()->get_depth_dose()[beam_idx]->lookup_energy(rgdepth);
 }
 
-void compute_dose_ray_desplanques (
-    Volume* dose_volume, 
-    Volume::Pointer ct_vol, 
+void
+compute_dose_a (
+    Volume::Pointer dose_vol, 
     Rt_beam* beam, 
-    Volume::Pointer final_dose_volume, 
-    int beam_index
+    const Volume::Pointer ct_vol
 )
 {
-    int ijk_idx[3] = {0,0,0};
-    int ijk_travel[3] = {0,0,0};
-    double xyz_travel[3] = {0.0,0.0,0.0};
-
-    double spacing[3] = { (double) (dose_volume->spacing[0]), (double) (dose_volume->spacing[1]), (double) (dose_volume->spacing[2])};
-    int ap_ij[2] = {1,0};
-    int dim[2] = {beam->sigma_vol->get_aperture()->get_dim(0),beam->sigma_vol->get_aperture()->get_dim(1)};
-    double ray_bev[3] = {0,0,0};
-    double xyz_ray_center[3] = {0.0, 0.0, 0.0};
-    double xyz_ray_pixel_center[3] = {0.0, 0.0, 0.0};
-    double entrance_bev[3] = {0.0f, 0.0f, 0.0f}; // coordinates of intersection with the volume in the bev frame
-    double xyz_room[3] = {0.0f, 0.0f, 0.0f}; 
-    double xyz_room_tmp[3] = {0.0f, 0.0f, 0.0f};
-    int ijk_ct[3] = {0,0,0};
-    double entrance_length = 0;
-    double distance = 0; // distance from the aperture to the POI
-    double tmp[3] = {0.0f, 0.0f, 0.0f};
-    double PB_density = 1/(beam->rpl_vol->get_aperture()->get_spacing(0) * beam->rpl_vol->get_aperture()->get_spacing(1));
-    double ct_density = 0;
-    double WER = 0;
-    double STPR = 0;
-    double sigma = 0;
-    int sigma_x3 = 0;
-    double rg_length = 0;
-    double radius = 0;
-    float range_comp = 0;
-    float central_axis_dose = 0;
-    float off_axis_factor = 0;
-
-    int idx = 0; // index to travel in the dose volume
-    int idx_bev = 0; // second index for reconstructing the final image
-    int idx_room = 0;
-    int i_min = 0;
-    int i_max = 0;
-    int j_min = 0;
-    int j_max = 0;
-	bool test = true;
-    bool* in = &test;
-
-    float* img = (float*) dose_volume->img;
-    float* ct_img = (float*) ct_vol->img;
-    float* rpl_image = (float*) beam->rpl_vol->get_vol()->img;
-    float* rc_img = 0;
-    unsigned char *ap_img = 0;
+    float* dose_img = (float*) dose_vol->img;
 
-    if (beam->get_aperture()->have_range_compensator_image())
-    {
-        rc_img = (float*) beam->get_aperture()->get_range_compensator_volume ()->img;
-    }
-	
-    if (beam->get_aperture()->have_aperture_image()) {
-        Volume::Pointer ap_vol = beam->get_aperture()->get_aperture_volume();
-        ap_img = (unsigned char*) ap_vol->img;
+    Aperture::Pointer& ap = beam->get_aperture ();
+    Volume *ap_vol = 0;
+    const unsigned char *ap_img = 0;
+    if (ap->have_aperture_image()) {
+        ap_vol = ap->get_aperture_vol ();
+        ap_img = ap_vol->get_raw<unsigned char> ();
     }
 
-	std::vector<float> num_part = beam->get_mebs()->get_num_particles();
-
-    double dist = 0;
-    int offset_step = 0;
-
-	double vec_pdn_tmp[3] = {0,0,0};
-	double vec_prt_tmp[3] = {0,0,0};
-	double vec_nrm_tmp[3] = {0,0,0};
-
-	vec3_copy(vec_pdn_tmp, beam->rpl_vol->get_proj_volume()->get_incr_c());
-	vec3_normalize1(vec_pdn_tmp);
-	vec3_copy(vec_prt_tmp, beam->rpl_vol->get_proj_volume()->get_incr_r());
-	vec3_normalize1(vec_prt_tmp);
-	vec3_copy(vec_nrm_tmp, beam->rpl_vol->get_proj_volume()->get_nrm());
-	vec3_normalize1(vec_nrm_tmp);
-
-    for (int i = 0; i < dim[0]*dim[1]; i++)
-    {
-		if (ap_img[i] == 0 || num_part[beam_index * dim[0] * dim[1] + i] == 0) 
-		{
-            continue;
-        }
-        
-		Ray_data* ray_data = &beam->sigma_vol->get_Ray_data()[i]; //MD Fix: Why ray_daya->ray for rpl_vol is wrong at this point?
-
-        ap_ij[1] = i / dim[0];
-        ap_ij[0] = i- ap_ij[1]*dim[0];
-        ray_bev[0] = vec3_dot (ray_data->ray, vec_prt_tmp);
-        ray_bev[1] = vec3_dot (ray_data->ray, vec_pdn_tmp);
-        ray_bev[2] = -vec3_dot (ray_data->ray, vec_nrm_tmp); // ray_beam_eye_view is already normalized
+    /* Dose D(POI) = Dose(z_POI) but z_POI =  rg_comp + depth in CT, 
+       if there is a range compensator */
+    if (ap->have_range_compensator_image()) {
+        add_rcomp_length_to_rpl_volume(beam);
+    }
 
-		/* printf("prt: %lg %lg %lg\n",vec_prt_tmp[0], vec_prt_tmp[1], vec_prt_tmp[2]);
-		printf("pdn: %lg %lg %lg\n",vec_pdn_tmp[0], vec_pdn_tmp[1], vec_pdn_tmp[2]);
-		printf("nrm: %lg %lg %lg\n",vec_nrm_tmp[0], vec_nrm_tmp[1], vec_nrm_tmp[2]);
-		printf("ray: %lg %lg %lg\n",ray_data->ray[0], ray_data->ray[1], ray_data->ray[2]);
-		printf("bev: %lg %lg %lg\n", ray_bev[0], ray_bev[1], ray_bev[2]); */
+    /* scan through patient CT Volume */
+    plm_long ct_ijk[3];
+    double ct_xyz[4];
+    plm_long idx = 0;
+    double idx_ap[2] = {0,0};
+    plm_long idx_ap_int[2] = {0,0};
+    double rest[2] = {0,0};
+    double particle_number = 0;
+    float WER = 0;
+    float rgdepth = 0;
 
-        /* Calculation of the coordinates of the intersection of the ray with the clipping plane */
-        entrance_length = vec3_dist(beam->rpl_vol->get_proj_volume()->get_src(), ray_data->cp);
+    for (ct_ijk[2] = 0; ct_ijk[2] < ct_vol->dim[2]; ct_ijk[2]++) {
+        for (ct_ijk[1] = 0; ct_ijk[1] < ct_vol->dim[1]; ct_ijk[1]++) {
+            for (ct_ijk[0] = 0; ct_ijk[0] < ct_vol->dim[0]; ct_ijk[0]++) {
+                double dose = 0.0;
 
-        vec3_copy(entrance_bev, ray_bev);
-        vec3_scale2(entrance_bev, entrance_length);
+                /* Transform vol index into space coords */
+                ct_xyz[0] = (double) (ct_vol->origin[0] + ct_ijk[0] * ct_vol->spacing[0]);
+                ct_xyz[1] = (double) (ct_vol->origin[1] + ct_ijk[1] * ct_vol->spacing[1]);
+                ct_xyz[2] = (double) (ct_vol->origin[2] + ct_ijk[2] * ct_vol->spacing[2]);
+                ct_xyz[3] = (double) 1.0;
 
-        if (beam->get_aperture()->have_range_compensator_image())
-        {
-            range_comp = rc_img[i] * PMMA_DENSITY * PMMA_STPR; // Lucite material: d * rho * WER
-        }
-        else
-        {
-            range_comp = 0;
-        }
-        if (ray_bev[2]  > DRR_BOUNDARY_TOLERANCE)
-        {
-            for(int k = 0; k < (int) dose_volume->dim[2] ;k++)
-            {
-                find_xyz_center(xyz_ray_center, ray_bev, dose_volume->origin[2],k, dose_volume->spacing[2]);
-                distance = vec3_dist(xyz_ray_center, entrance_bev);
-				ct_density = compute_density_from_HU(beam->rpl_ct_vol_HU->get_rgdepth(ap_ij, distance));
-                STPR = compute_PrSTPR_from_HU(beam->rpl_ct_vol_HU->get_rgdepth(ap_ij, distance));
-                rg_length = range_comp + beam->rpl_vol->get_rgdepth(ap_ij, distance);
-                central_axis_dose = beam->get_mebs()->get_depth_dose()[beam_index]->lookup_energy_integration((float)rg_length, ct_density * dose_volume->spacing[2]) * STPR;
-                sigma = beam->sigma_vol->get_rgdepth(ap_ij, distance);
-                sigma_x3 = (int) ceil(3 * sigma);
-
-                /* We defined the grid to be updated, the pixels that receive dose from the ray */
-                /* We don't check to know if we are still in the matrix because the matrix was build to contain all pixels with a 3 sigma_max margin */
-                find_ijk_pixel(ijk_idx, xyz_ray_center, dose_volume);
-                i_min = ijk_idx[0] - sigma_x3;
-                i_max = ijk_idx[0] + sigma_x3;
-                j_min = ijk_idx[1] - sigma_x3;
-                j_max = ijk_idx[1] + sigma_x3;
-                for (int i2 = i_min; i2 <= i_max; i2++)
+                if (beam->get_intersection_with_aperture(idx_ap, idx_ap_int, rest, ct_xyz) == false)
                 {
-                    for (int j2 = j_min; j2 <= j_max; j2++)
-                    {
-                        if (i2 < 0 || j2 < 0 || i2 >= dose_volume->dim[0] || j2 >= dose_volume->dim[1])
-                        {
-                            continue;
-                        }
-                        idx = i2 + (dose_volume->dim[0] * (j2 + dose_volume->dim[1] * k));
-                        ijk_travel[0] = i2;
-                        ijk_travel[1] = j2;
-                        ijk_travel[2] = k;
-
-                        /* calculation of the corresponding position in the room and its HU number*/
-                        vec3_copy(xyz_room_tmp, vec_prt_tmp);
-                        vec3_scale2(xyz_room_tmp, dose_volume->origin[0] + (float) i2 * dose_volume->spacing[0]);
-                        vec3_copy(xyz_room, (xyz_room_tmp));
-
-                        vec3_copy(xyz_room_tmp, vec_pdn_tmp);
-                        vec3_scale2(xyz_room_tmp, dose_volume->origin[1] + (float) j2 * dose_volume->spacing[1]);
-                        vec3_add2(xyz_room, (xyz_room_tmp));
-
-                        vec3_copy(xyz_room_tmp,  vec_nrm_tmp);
-                        vec3_scale2(xyz_room_tmp, (double) (-dose_volume->origin[2] - (float) k * dose_volume->spacing[2]));
-                        vec3_add2(xyz_room, (xyz_room_tmp));
-                        vec3_add2(xyz_room, beam->rpl_vol->get_proj_volume()->get_src());
-						
-                        find_ijk_pixel(ijk_ct, xyz_room, ct_vol);
-                        idx_room = ijk_ct[0] + (ct_vol->dim[0] * (ijk_ct[1] + ct_vol->dim[1] * ijk_ct[2]));
-                        if (ijk_ct[0] < 0 || ijk_ct[1] < 0 || ijk_ct[2] < 0 || ijk_ct[0] >= ct_vol->dim[0] || ijk_ct[1] >= ct_vol->dim[1] || ijk_ct[2] >= ct_vol->dim[2])
-                        {
-                            WER = PROTON_WER_AIR;
-                        }
-                        else
-                        {
-                            WER =  compute_PrWER_from_HU(ct_img[idx_room]);
-                        }
-                        find_xyz_from_ijk(xyz_travel,dose_volume,ijk_travel);
-                        radius = vec3_dist(xyz_travel,xyz_ray_center); 
-                        if (sigma == 0)
-                        {
-                            off_axis_factor = 1;
-                        }
-                        else if (radius > sqrt(0.25 * spacing[0] * spacing [0] + 0.25 * spacing[1] * spacing[1]) + 3 * sigma )
-                        {
-                            off_axis_factor = 0;
-                        }
-                        else
-                        {
-                            off_axis_factor = double_gaussian_interpolation(xyz_ray_center, xyz_travel,sigma, spacing);
-                        }
-                        /* SOBP is weighted by the weight of the pristine peak */
-                        img[idx] += num_part[beam_index * dim[0] * dim[1] + i] * central_axis_dose 
-                            * WER // dose = dose_w * WER
-                            * off_axis_factor ;
-                    }			
+                    continue;
                 }
-            }
-        }
-    }
 
-    float* final_dose_img = (float*) final_dose_volume->img;
-    int ijk[3] = {0,0,0};
-    float ijk_bev[3] = {0,0,0};
-    int ijk_bev_trunk[3];
-    float xyz_bev[3] = {0.0,0.0,0.0};
-    plm_long mijk_f[3];
-    plm_long mijk_r[3];
-    plm_long idx_lower_left = 0;
-    float li_frac1[3];
-    float li_frac2[3];
-    const plm_long *dim_ct = ct_vol->dim;
-    plm_long dose_bev_dim[3] = { dose_volume->dim[0], dose_volume->dim[1], dose_volume->dim[2]};
-
-    for (ijk[0] = 0; ijk[0] < dim_ct[0]; ijk[0]++)
-    {
-        for (ijk[1] = 0; ijk[1] < dim_ct[1]; ijk[1]++)
-        {
-            for (ijk[2] = 0; ijk[2] < dim_ct[2]; ijk[2]++)
-            {
-                idx = ijk[0] + dim_ct[0] *(ijk[1] + ijk[2] * dim_ct[1]);
-                if ( ct_img[idx] >= -1000) // in air we have no dose, we let the voxel number at 0!
-                {   
-                    final_dose_volume->get_xyz_from_ijk(xyz_room, ijk);
+                /* Check that the ray cross the aperture */
+                if (idx_ap[0] < 0 || idx_ap[0] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(0)-1
+                    || idx_ap[1] < 0 || idx_ap[1] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(1)-1)
+                {
+                    continue;
+                }
 
-                    /* xyz contains the coordinates of the pixel in the room coordinates */
-                    /* we now calculate the coordinates of this pixel in the dose_volume coordinates */
+                /* Check that the ray cross the active part of the aperture */
+                if (ap_img && beam->is_ray_in_the_aperture(idx_ap_int, ap_img) == false)
+                {
+                    continue;
+                }
 
-                    vec3_sub3(tmp,  beam->rpl_vol->get_proj_volume()->get_src(), xyz_room);
-                    xyz_bev[0] = (float) -vec3_dot(tmp, vec_prt_tmp);
-                    xyz_bev[1] = (float) -vec3_dot(tmp,  vec_pdn_tmp);
-                    xyz_bev[2] = (float) vec3_dot(tmp,  vec_nrm_tmp);
-                    dose_volume->get_ijk_from_xyz(ijk_bev, xyz_bev, in);
+                dose = 0;
+                rgdepth = beam->rsp_accum_vol->get_value (ct_xyz);
+                WER = compute_PrWER_from_HU (beam->hu_samp_vol->get_value(ct_xyz));
 
-                    if (*in == true)
+                const Rt_mebs::Pointer& mebs = beam->get_mebs();
+                for (size_t dd_idx = 0; dd_idx < mebs->get_depth_dose().size(); dd_idx++)
+                {
+                    particle_number = mebs->get_particle_number_xyz (idx_ap_int, rest, dd_idx, beam->get_aperture()->get_dim());
+                    if (particle_number != 0 && rgdepth >=0 && rgdepth < mebs->get_depth_dose()[dd_idx]->dend) 
                     {
-                        dose_volume->get_ijk_from_xyz(ijk_bev_trunk, xyz_bev, in);
-                        idx_bev = ijk_bev_trunk[0] + ijk_bev[1]*dose_volume->dim[0] + ijk_bev[2] * dose_volume->dim[0] * dose_volume->dim[1];
-                        li_clamp_3d(ijk_bev, mijk_f, mijk_r, li_frac1, li_frac2, dose_volume);
-                        idx_lower_left =  mijk_f[0] + dose_bev_dim[0] *(mijk_f[1] + mijk_f[2] * dose_bev_dim[1]);
-                        final_dose_img[idx] += li_value(li_frac1[0], li_frac2[0], li_frac1[1], li_frac2[1], li_frac1[2], li_frac2[2], idx_lower_left, img, dose_volume);
+                        dose += particle_number * WER * energy_direct (rgdepth, beam, dd_idx);
                     }
                 }
-            }   
-        }     
+
+                /* Insert the dose into the dose volume */
+                idx = volume_index (dose_vol->dim, ct_ijk);
+                dose_img[idx] = dose;
+            }
+        }
     }
-    return;
 }
 
-void 
-compute_dose_ray_sharp (
-    const Volume::Pointer ct_vol, 
-    Rt_beam* beam, 
-    Rpl_volume* rpl_dose_volume,  
-    int beam_index,
-    const int* margins
+void
+compute_dose_b (
+    Rt_beam* beam,
+    size_t energy_index,
+    const Volume::Pointer ct_vol
 )
 {
-    int ap_ij_lg[2] = {0,0};
-    int ap_ij_sm[2] = {0,0};
-    int dim_lg[3] = {0,0,0};
-    int dim_sm[3] = {0,0,0};
-    const plm_long *dim_ct = ct_vol->dim;
-    int idx2d_sm = 0;
-    int idx2d_lg = 0;
-    int idx3d_sm = 0;
-    int idx3d_lg = 0;
-    int idx3d_travel = 0;
-    int idx_ct = 0;
-    int ijk_ct[3] = {0,0,0};
-    int i_min = 0;
-    int i_max = 0;
-    int j_min = 0;
-    int j_max = 0;
-
-    float ct_density = 0;
-    float WER = 0;
-    float DENSITY = 0;
-    float STPR = 0;
-    double sigma = 0;
-    double sigma_x3 = 0;
-    double rg_length = 0;
-    float central_axis_dose = 0;
-    float off_axis_factor = 0;
-    double minimal_lateral = 0;
-    double lateral_step[2] = {0,0};
-    double central_ray_xyz[3] = {0.0, 0.0, 0.0};
-    double travel_ray_xyz[3] = {0.0, 0.0, 0.0};
-    double xyz_room[4] = {0.0, 0.0, 0.0, 1.0};
-    double PB_density = 1 / ( beam->rpl_vol->get_aperture()->get_spacing(0) *  beam->rpl_vol->get_aperture()->get_spacing(1));
-
-    dim_lg[0] = rpl_dose_volume->get_vol()->dim[0];
-    dim_lg[1] = rpl_dose_volume->get_vol()->dim[1];
-    dim_lg[2] = rpl_dose_volume->get_vol()->dim[2];
-    dim_sm[0] = beam->rpl_vol->get_vol()->dim[0];
-    dim_sm[1] = beam->rpl_vol->get_vol()->dim[1];
-    dim_sm[2] = beam->rpl_vol->get_vol()->dim[2];
-	
-    float* rpl_img = (float*) beam->rpl_vol->get_vol()->img;
-    float* sigma_img = (float*) beam->sigma_vol->get_vol()->img;
-    float* rpl_dose_img = (float*) rpl_dose_volume->get_vol()->img;
-    float* ct_rpl_img = (float*) beam->rpl_ct_vol_HU->get_vol()->img;
-    float* ct_img = (float*) ct_vol->img;
-    float* rc_img = 0;
-    unsigned char *ap_img = 0;
-    float range_comp = 0;
-
-    Ray_data* ray_data;
-    Ray_data* ray_data_tmp;
-	
-    if (beam->get_aperture()->have_aperture_image()) {
-        Volume::Pointer ap_vol = beam->get_aperture()->get_aperture_volume();
-        ap_img = (unsigned char*) ap_vol->img;
-    }
-
-    if (beam->get_aperture()->have_range_compensator_image())
-    {
-        rc_img = (float*) beam->get_aperture()->get_range_compensator_volume ()->img;
+    Rpl_volume *wepl_rv = beam->rsp_accum_vol;
+    Volume *wepl_vol = wepl_rv->get_vol();
+    float *wepl_img = wepl_vol->get_raw<float> ();
+
+    Rpl_volume *dose_rv = beam->dose_rv;
+    Volume *dose_rv_vol = dose_rv->get_vol();
+    float *dose_rv_img = dose_rv_vol->get_raw<float> ();
+
+    Rt_mebs::Pointer mebs = beam->get_mebs();
+    const Rt_depth_dose *depth_dose = mebs->get_depth_dose()[energy_index];
+    std::vector<float>& num_part = mebs->get_num_particles();
+
+    /* scan through rpl volume */
+    Aperture::Pointer& ap = beam->get_aperture ();
+    Volume *ap_vol = 0;
+    const unsigned char *ap_img = 0;
+    if (ap->have_aperture_image()) {
+        ap_vol = ap->get_aperture_vol ();
+        ap_img = ap_vol->get_raw<unsigned char> ();
     }
-    double dist = 0;
-    double radius = 0;
-
-    /* Creation of the rpl_volume containing the coordinates xyz (beam eye view) and the CT density vol*/
-    std::vector<double> xyz_init (4,0);
-    std::vector< std::vector<double> > xyz_coor_vol (dim_lg[0]*dim_lg[1]*dim_lg[2], xyz_init);
-    calculate_rpl_coordinates_xyz (&xyz_coor_vol, rpl_dose_volume);
-
-    for (int m = 0; m < dim_lg[0] * dim_lg[1] * dim_lg[2]; m++)
-    {
-        rpl_dose_img[m] = 0;
+    const plm_long *dim = wepl_rv->get_image_dim();
+    int num_steps = wepl_rv->get_num_steps();
+    plm_long ij[2] = {0,0};
+    for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) {
+        for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) {
+            if (ap_img && ap_img[ap_vol->index(ij[0],ij[1],0)] == 0) {
+                continue;
+            }
+            size_t np_index = energy_index * dim[0] * dim[1]
+                + ij[1] * dim[0] + ij[0];
+            float np = num_part[np_index];
+            if (np == 0.f) {
+                continue;
+            }
+            for (int s = 0; s < num_steps; s++) {
+                int dose_index = ap_vol->index(ij[0],ij[1],s);
+                float wepl = wepl_img[dose_index];
+                dose_rv_img[dose_index] += np * depth_dose->lookup_energy(wepl);
+            }
+        }
     }
+}
 
-    /* calculation of the lateral steps in which the dose is searched constant with depth */
-    std::vector <double> lateral_minimal_step (dim_lg[2],0);
-    std::vector <double> lateral_step_x (dim_lg[2],0);
-    std::vector <double> lateral_step_y (dim_lg[2],0);
-
-    minimal_lateral = beam->get_aperture()->get_spacing(0);
-    if (minimal_lateral < beam->get_aperture()->get_spacing(1))
-    {
-        minimal_lateral = beam->get_aperture()->get_spacing(1);
-    }
+void
+compute_dose_ray_trace_dij_a (
+    Rt_beam* beam,
+    size_t energy_index,
+    const Volume::Pointer ct_vol,
+    Volume::Pointer& dose_vol
+)
+{
+    float* dose_img = (float*) dose_vol->img;
 
-    for (int k = 0; k < dim_sm[2]; k++)
+    /* Dose D(POI) = Dose(z_POI) but z_POI =  rg_comp + depth in CT, 
+       if there is a range compensator */
+    if (beam->get_aperture()->have_range_compensator_image())
     {
-        lateral_minimal_step[k] = (beam->rpl_vol->get_front_clipping_plane() + beam->rpl_vol->get_aperture()->get_distance() + (double) k) * minimal_lateral / beam->rpl_vol->get_aperture()->get_distance();
-        lateral_step_x[k] = (beam->rpl_vol->get_front_clipping_plane() + beam->rpl_vol->get_aperture()->get_distance() + (double) k) * beam->get_aperture()->get_spacing(0) / beam->rpl_vol->get_aperture()->get_distance();
-        lateral_step_y[k] = (beam->rpl_vol->get_front_clipping_plane() + beam->rpl_vol->get_aperture()->get_distance() + (double) k) *beam->get_aperture()->get_spacing(1) / beam->rpl_vol->get_aperture()->get_distance();
+        add_rcomp_length_to_rpl_volume(beam);
     }
 
-    std::vector<float> num_part = beam->get_mebs()->get_num_particles();
+    /* scan through patient CT Volume */
+    plm_long ct_ijk[3];
+    double ct_xyz[4];
+    plm_long idx = 0;
+    double idx_ap[2] = {0,0};
+    plm_long idx_ap_int[2] = {0,0};
+    double rest[2] = {0,0};
+    unsigned char* ap_img = (unsigned char*) beam->get_aperture()->get_aperture_volume()->img;
+    double particle_number = 0;
+    float WER = 0;
+    float rgdepth = 0;
 
-    /* calculation of the dose in the rpl_volume */
-    for (ap_ij_lg[0] = margins[0]; ap_ij_lg[0] < rpl_dose_volume->get_vol()->dim[0]-margins[0]; ap_ij_lg[0]++){
-        for (ap_ij_lg[1] = margins[1]; ap_ij_lg[1] < rpl_dose_volume->get_vol()->dim[1]-margins[1]; ap_ij_lg[1]++){
+    for (ct_ijk[2] = 0; ct_ijk[2] < ct_vol->dim[2]; ct_ijk[2]++) {
+        for (ct_ijk[1] = 0; ct_ijk[1] < ct_vol->dim[1]; ct_ijk[1]++) {
+            for (ct_ijk[0] = 0; ct_ijk[0] < ct_vol->dim[0]; ct_ijk[0]++) {
+                double dose = 0.0;
 
-            ap_ij_sm[0] = ap_ij_lg[0] - margins[0];
-            ap_ij_sm[1] = ap_ij_lg[1] - margins[1];
-            idx2d_lg = ap_ij_lg[1] * dim_lg[0] + ap_ij_lg[0];
-            idx2d_sm = ap_ij_sm[1] * dim_sm[0] + ap_ij_sm[0];
+                /* Transform vol index into space coords */
+                ct_xyz[0] = (double) (ct_vol->origin[0] + ct_ijk[0] * ct_vol->spacing[0]);
+                ct_xyz[1] = (double) (ct_vol->origin[1] + ct_ijk[1] * ct_vol->spacing[1]);
+                ct_xyz[2] = (double) (ct_vol->origin[2] + ct_ijk[2] * ct_vol->spacing[2]);
+                ct_xyz[3] = (double) 1.0;
 
-            if (beam->get_aperture()->have_aperture_image())
-            {
-                if((float) ap_img[idx2d_sm] == 0 || num_part[beam_index * beam->get_aperture()->get_dim(0) * beam->get_aperture()->get_dim(1) + idx2d_sm] == 0)
+                if (beam->get_intersection_with_aperture (idx_ap, idx_ap_int, rest, ct_xyz) == false)
                 {
                     continue;
                 }
-            }
-            if (beam->get_aperture()->have_range_compensator_image())
-            {
-                range_comp = rc_img[idx2d_sm] * PMMA_DENSITY * PMMA_STPR; // Lucite Material: d * rho * WER, MD Fix
-            }
-            else
-            {
-                range_comp = 0;
-            }
-
-            ray_data = &rpl_dose_volume->get_Ray_data()[idx2d_lg];
-            for (int k = 0; k < dim_sm[2]; k++)
-            {
-                idx3d_lg = idx2d_lg + k * dim_lg[0]*dim_lg[1];
-                idx3d_sm = idx2d_sm + k * dim_sm[0]*dim_sm[1];
-
-                central_ray_xyz[0] = xyz_coor_vol[idx3d_lg][0];
-                central_ray_xyz[1] = xyz_coor_vol[idx3d_lg][1];
-                central_ray_xyz[2] = xyz_coor_vol[idx3d_lg][2];
-
-                lateral_step[0] = lateral_step_x[k];
-                lateral_step[1] = lateral_step_x[k];
 
-                ct_density = compute_density_from_HU(ct_rpl_img[idx3d_sm]);
-                STPR = compute_PrSTPR_from_HU(ct_rpl_img[idx3d_sm]);
-
-                rg_length = range_comp + rpl_img[idx3d_sm];
-                central_axis_dose = num_part[beam_index * beam->get_aperture()->get_dim(0)* beam->get_aperture()->get_dim(1) + idx2d_sm] * beam->get_mebs()->get_depth_dose()[beam_index]->lookup_energy_integration(rg_length, ct_density * beam->rpl_vol->get_vol()->spacing[2]) * STPR;
+                /* Check that the ray cross the aperture */
+                if (idx_ap[0] < 0 || idx_ap[0] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(0)-1
+                    || idx_ap[1] < 0 || idx_ap[1] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(1)-1)
+                {
+                    continue;
+                }
 
-                if (central_axis_dose <= 0) // no dose on the axis, no dose scattered
+                /* Check that the ray cross the active part of the aperture */
+                if (beam->get_aperture()->have_aperture_image() && beam->is_ray_in_the_aperture (idx_ap_int, ap_img) == false)
                 {
                     continue;
                 }
 
-                sigma = (double) sigma_img[idx3d_sm];
-                sigma_x3 = sigma * 3;
+                dose = 0;
+                rgdepth = beam->rsp_accum_vol->get_value (ct_xyz);
+                WER = compute_PrWER_from_HU (beam->hu_samp_vol->get_value(ct_xyz));
 
-                /* finding the rpl_volume pixels that are contained in the the 3 sigma range */                    
-                i_min = ap_ij_lg[0] - (int) ceil(sigma_x3 / lateral_minimal_step[k]);
-                if (i_min < 0 ) {i_min = 0;}
-                i_max = ap_ij_lg[0] + (int) ceil(sigma_x3 / lateral_minimal_step[k]);
-                if (i_max > dim_lg[0]-1 ) {i_max = dim_lg[0]-1;}
-                j_min = ap_ij_lg[1] - (int) ceil(sigma_x3 / lateral_minimal_step[k]);
-                if (j_min < 0 ) {j_min = 0;}
-                j_max = ap_ij_lg[1] + (int) ceil(sigma_x3 / lateral_minimal_step[k]);
-                if (j_max > dim_lg[1]-1 ) {j_max = dim_lg[1]-1;}
+                const Rt_mebs::Pointer& mebs = beam->get_mebs();
+                for (size_t dd_idx = 0; dd_idx < mebs->get_depth_dose().size(); dd_idx++)
+                {
+                    particle_number = mebs->get_particle_number_xyz (idx_ap_int, rest, dd_idx, beam->get_aperture()->get_dim());
+                    if (particle_number != 0 && rgdepth >=0 && rgdepth < mebs->get_depth_dose()[dd_idx]->dend) 
+                    {
+                        dose += particle_number * WER * energy_direct (rgdepth, beam, dd_idx);
+                    }
+                }
 
-                for (int i1 = i_min; i1 <= i_max; i1++) {
-                    for (int j1 = j_min; j1 <= j_max; j1++) {
-                        idx3d_travel = k * dim_lg[0]*dim_lg[1] + j1 * dim_lg[0] + i1;
+                /* Insert the dose into the dose volume */
+                idx = volume_index (dose_vol->dim, ct_ijk);
+                dose_img[idx] = dose;
+            }
+        }
+    }
+}
 
-                        ray_data_tmp = &rpl_dose_volume->get_Ray_data()[j1 * dim_lg[0] + i1];
+void
+compute_dose_ray_trace_dij_b (
+    Rt_beam* beam,
+    const Volume::Pointer ct_vol,
+    Volume::Pointer& dose_vol
+)
+{
+    Rpl_volume *wepl_rv = beam->rsp_accum_vol;
+    Volume *wepl_vol = wepl_rv->get_vol();
+    float *wepl_img = wepl_vol->get_raw<float> ();
+
+    Rpl_volume *dose_rv = beam->dose_rv;
+    Volume *dose_rv_vol = dose_rv->get_vol();
+    float *dose_rv_img = dose_rv_vol->get_raw<float> ();
+
+    Rt_mebs::Pointer mebs = beam->get_mebs();
+    const std::vector<Rt_depth_dose*> depth_dose = mebs->get_depth_dose();
+    std::vector<float>& num_part = mebs->get_num_particles();
+
+    /* Create the beamlet dij matrix */
+    Rt_dij rt_dij;
+
+    /* Create geometry map from volume to rpl_volume */
+    Rpl_volume_lut rpl_volume_lut (dose_rv, dose_vol.get());
+    rpl_volume_lut.build_lut ();
+
+    /* scan through rpl volume */
+    Aperture::Pointer& ap = beam->get_aperture ();
+    Volume *ap_vol = 0;
+    const unsigned char *ap_img = 0;
+    if (ap->have_aperture_image()) {
+        ap_vol = ap->get_aperture_vol ();
+        ap_img = ap_vol->get_raw<unsigned char> ();
+    }
+    const plm_long *dim = wepl_rv->get_image_dim();
+    int num_steps = wepl_rv->get_num_steps();
+    plm_long ij[2] = {0,0};
+    for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) {
+        for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) {
+            if (ap_img && ap_img[ap_vol->index(ij[0],ij[1],0)] == 0) {
+                continue;
+            }
+            for (size_t energy_index = 0; 
+                 energy_index < depth_dose.size(); 
+                 energy_index++)
+            {
+                // Get beamlet weight
+                size_t np_index = energy_index * dim[0] * dim[1]
+                    + ij[1] * dim[0] + ij[0];
+                float np = num_part[np_index];
+                if (np == 0.f) {
+                    continue;
+                }
 
-                        travel_ray_xyz[0] = xyz_coor_vol[idx3d_travel][0];
-                        travel_ray_xyz[1] = xyz_coor_vol[idx3d_travel][1];
-                        travel_ray_xyz[2] = xyz_coor_vol[idx3d_travel][2];
-                        radius = vec3_dist(travel_ray_xyz, central_ray_xyz);
+                // Fill in dose
+                const Rt_depth_dose *dd = depth_dose[energy_index];
+                for (int s = 0; s < num_steps; s++) {
+                    int dose_index = ap_vol->index(ij[0],ij[1],s);
+                    float wepl = wepl_img[dose_index];
+                    dose_rv_img[dose_index] = np * dd->lookup_energy(wepl);
+                }
 
-                        if (sigma == 0)
-                        {
-                            off_axis_factor = 1;
-                        }
-                        else
-                        {
-                            off_axis_factor = double_gaussian_interpolation(central_ray_xyz, travel_ray_xyz, sigma, lateral_step);
-                        }
+                // Create beamlet dij
+                rt_dij.set_from_dose_rv (
+                    ij, energy_index, dose_rv, ct_vol);
 
-                        vec3_copy(xyz_room, ray_data_tmp->ray);
-                        vec3_scale2(xyz_room, rpl_dose_volume->get_aperture()->get_distance() + rpl_dose_volume->get_front_clipping_plane() + (double) k);
-                        vec3_add2(xyz_room, rpl_dose_volume->get_proj_volume()->get_src());
-                        find_ijk_pixel(ijk_ct, xyz_room, ct_vol);
-                        if (ijk_ct[0] < 0 || ijk_ct[0] >= dim_ct[0] || ijk_ct[1] < 0 || ijk_ct[1] >= dim_ct[1] || ijk_ct[2] < 0 || ijk_ct[2] >= dim_ct[2] )
-                        {
-                            WER = PROTON_WER_AIR;
-                            DENSITY = AIR_DENSITY;
-                        }
-                        else
-                        {
-                            WER = compute_PrWER_from_HU(ct_img[ijk_ct[2] * dim_ct[0]*dim_ct[1] + ijk_ct[1] * dim_ct[0] + ijk_ct[0] ] );
-                            DENSITY = compute_density_from_HU(ct_img[ijk_ct[2] * dim_ct[0]*dim_ct[1] + ijk_ct[1] * dim_ct[0] + ijk_ct[0] ] );
-                        }
-                        if (DENSITY > 0.8)
-                        {
-                            rpl_dose_img[idx3d_travel] += central_axis_dose 
-                                * WER / DENSITY
-                                * off_axis_factor ;
-                        }
-                    } //for j1
-                } //for i1
-            } // for k
-        } // ap_ij[1]
-    } // ap_ij[0]   
+                // Zero out again
+                for (int s = 0; s < num_steps; s++) {
+                    int dose_index = ap_vol->index(ij[0],ij[1],s);
+                    dose_rv_img[dose_index] = 0.f;
+                }
+            }
+        }
+    }
+
+    // Write beamlet dij
+    if (beam->get_dij_out() != "") {
+        rt_dij.dump (beam->get_dij_out());
+    }
 }
 
-void compute_dose_ray_shackleford (
-    Volume::Pointer dose_vol,
-    Rt_plan* plan,
+void
+compute_dose_d (
     Rt_beam* beam,
-    int beam_index,
-    std::vector<double>* area,
-    std::vector<double>* xy_grid,
-    int radius_sample,
-    int theta_sample)
+    size_t energy_index,
+    const Volume::Pointer ct_vol
+)
 {
-    int ijk[3] = {0,0,0};
-    double xyz[4] = {0,0,0,1};
-    double xyz_travel[4] = {0,0,0,1};
-    double tmp_xy[4] = {0,0,0,1};
-    double tmp_cst = 0;
-    int idx = 0;
-    const plm_long *dose_dim = dose_vol->dim;
-    double vec_ud[4] = {0,0,0,1};
-    double vec_rl[4] = {0,0,0,1};
-    float* ct_img = (float*) plan->get_patient_volume()->img;
-    float* dose_img = (float*) dose_vol->img;
-    double sigma_travel = 0;
-    double sigma_3 = 0;
-    double rg_length = 0;
-    float ct_density = 0;
-    float STPR = 0;
-    float HU = 0;
-    double central_sector_dose = 0;
-    double radius = 0;
-    double theta = 0;
-    double dr = 0;
-
-    double idx_ap[2] = {0,0};
-    int idx_ap_int[2] = {0,0};
-    double rest[2] = {0,0};
-    float particle_number = 0;
+    beam->get_rt_dose_timing()->timer_dose_calc.resume ();
+    Rpl_volume *wepl_rv = beam->rsp_accum_vol;
+    Volume *wepl_vol = wepl_rv->get_vol();
+    float *wepl_img = wepl_vol->get_raw<float> ();
+
+    Rpl_volume *dose_rv = beam->dose_rv;
+    Volume *dose_rv_vol = dose_rv->get_vol();
+    float *dose_rv_img = dose_rv_vol->get_raw<float> ();
+
+    Rt_mebs::Pointer mebs = beam->get_mebs();
+    const Rt_depth_dose *depth_dose = mebs->get_depth_dose()[energy_index];
+    std::vector<float>& num_part = mebs->get_num_particles();
+    beam->get_rt_dose_timing()->timer_dose_calc.stop ();
+
+    // Compute sigma for this energy
+    beam->get_rt_dose_timing()->timer_sigma.resume ();
+    int margins[2] = {0,0};
+    float sigma_max = 0;
+    compute_sigmas (beam, depth_dose->E0, &sigma_max, "small", margins);
+    beam->get_rt_dose_timing()->timer_sigma.stop ();
+
+    beam->get_rt_dose_timing()->timer_dose_calc.resume ();
+    Rpl_volume *sigma_rv = beam->sigma_vol;
+    Volume *sigma_vol = sigma_rv->get_vol();
+    float *sigma_img = sigma_vol->get_raw<float> ();
+    const plm_long *sigma_dim = sigma_vol->get_dim();
+
+    // Get the variable magnification at each step
+    std::vector <double> lateral_spacing_0 (sigma_dim[2],0);
+    std::vector <double> lateral_spacing_1 (sigma_dim[2],0);
+    double sid = sigma_rv->get_aperture()->get_distance();
+    const double *ap_spacing = sigma_rv->get_aperture()->get_spacing();
+    float clipping_dist = sigma_rv->get_front_clipping_plane();
+    float step_length = sigma_rv->get_step_length ();
+    for (int k = 0; k < sigma_dim[2]; k++) {
+        float mag = (sid + clipping_dist + k * step_length) / sid;
+        lateral_spacing_0[k] = ap_spacing[0] * mag;
+        lateral_spacing_1[k] = ap_spacing[1] * mag;
+    }
 
-    unsigned char *ap_img = 0;	
-    if (beam->get_aperture()->have_aperture_image()) {
-        Volume::Pointer ap_vol = beam->get_aperture()->get_aperture_volume();
-        ap_img = (unsigned char*) ap_vol->img;
+    // Compute lateral search distance (2.5 max sigma) for each depth
+    // (Only needed if pulling dose, not needed if pushing)
+    // GCS FIX: This need only be computed once per beam, not once per energy
+    std::vector <int> lateral_step_0 (sigma_dim[2],0);
+    std::vector <int> lateral_step_1 (sigma_dim[2],0);
+    for (int k = 0; k < sigma_dim[2]; k++) {
+        float sigma_max = 0.f;
+        for (int i = 0; i < sigma_dim[0]*sigma_dim[1]; i++) {
+            plm_long idx = k*sigma_dim[0]*sigma_dim[1] + i;
+            if (sigma_img[idx] > sigma_max) {
+                sigma_max = sigma_img[idx];
+            }
+        }
+        lateral_step_0[k] = ceil (2.5 * sigma_max / lateral_spacing_0[k]);
+        lateral_step_1[k] = ceil (2.5 * sigma_max / lateral_spacing_1[k]);
     }
 
-    /* Dose D(POI) = Dose(z_POI) but z_POI =  rg_comp + depth in CT, if there is a range compensator */
-    if (beam->rpl_vol->get_aperture()->have_range_compensator_image())
-    {
-        add_rcomp_length_to_rpl_volume(beam);
+    // Create central axis dose volume
+    Rpl_volume *cax_dose_rv = new Rpl_volume;
+    if (!cax_dose_rv) return;
+    cax_dose_rv->clone_geometry (wepl_rv);
+    cax_dose_rv->set_ray_trace_start (RAY_TRACE_START_AT_CLIPPING_PLANE);
+    cax_dose_rv->set_aperture (beam->get_aperture());
+    cax_dose_rv->set_ct (wepl_rv->get_ct());
+    cax_dose_rv->set_ct_limit (wepl_rv->get_ct_limit());
+    cax_dose_rv->compute_ray_data();
+    cax_dose_rv->set_front_clipping_plane (wepl_rv->get_front_clipping_plane());
+    cax_dose_rv->set_back_clipping_plane (wepl_rv->get_back_clipping_plane());
+    cax_dose_rv->compute_rpl_void ();
+    Volume *cax_dose_vol = cax_dose_rv->get_vol ();
+    float *cax_dose_img = cax_dose_vol->get_raw<float> ();
+    
+    // Compute central axis dose
+    Aperture::Pointer& ap = beam->get_aperture ();
+    Volume *ap_vol = 0;
+    const unsigned char *ap_img = 0;
+    if (ap->have_aperture_image()) {
+        ap_vol = ap->get_aperture_vol ();
+        ap_img = ap_vol->get_raw<unsigned char> ();
+    }
+    const plm_long *dim = wepl_rv->get_image_dim();
+    plm_long num_steps = wepl_rv->get_num_steps();
+    plm_long ij[2] = {0,0};
+    for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) {
+        for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) {
+            if (ap_img && ap_img[ap_vol->index(ij[0],ij[1],0)] == 0) {
+                continue;
+            }
+            size_t np_index = energy_index * dim[0] * dim[1]
+                + ij[1] * dim[0] + ij[0];
+            float np = num_part[np_index];
+            if (np == 0.f) {
+                continue;
+            }
+            for (int s = 0; s < num_steps; s++) {
+                int dose_index = ap_vol->index(ij[0],ij[1],s);
+                float wepl = wepl_img[dose_index];
+                cax_dose_img[dose_index] += np * depth_dose->lookup_energy(wepl);
+            }
+        }
     }
-    vec3_copy(vec_ud, beam->rpl_vol->get_proj_volume()->get_incr_c());
-    vec3_normalize1(vec_ud);
-    vec3_copy(vec_rl, beam->rpl_vol->get_proj_volume()->get_incr_r());
-    vec3_normalize1(vec_rl);
-
-    for (ijk[0] = 0; ijk[0] < dose_dim[0]; ijk[0]++){
-        printf("%d ", ijk[0]);
-        for (ijk[1] = 0; ijk[1] < dose_dim[1]; ijk[1]++){
-            for (ijk[2] = 0; ijk[2] < dose_dim[2]; ijk[2]++){
-                idx = ijk[0] + dose_dim[0] * (ijk[1] + dose_dim[1] * ijk[2]);
-
-                /* calculation of the pixel coordinates in the room coordinates */
-                xyz[0] = (double) dose_vol->origin[0] + ijk[0] * dose_vol->spacing[0];
-                xyz[1] = (double) dose_vol->origin[1] + ijk[1] * dose_vol->spacing[1];
-                xyz[2] = (double) dose_vol->origin[2] + ijk[2] * dose_vol->spacing[2]; // xyz[3] always = 1.0
-                sigma_3 = 3 * beam->sigma_vol_lg->get_rgdepth(xyz);
-
-                for (int i = 0; i < radius_sample; i++)
-                {
-                    for (int j =0; j < theta_sample; j++)
-                    {
-                        vec3_copy(xyz_travel, xyz);
-
-                        /* calculation of the center of the sector */
-                        vec3_copy(tmp_xy, vec_ud);
-                        tmp_cst = (double) (*xy_grid)[2*(i*theta_sample+j)] * sigma_3; // xy_grid is normalized to a circle of radius sigma x 3 = 1
-                        vec3_scale2(tmp_xy, tmp_cst);
-                        vec3_add2(xyz_travel,tmp_xy);
-
-                        vec3_copy(tmp_xy, vec_rl);
-                        tmp_cst = (double) (*xy_grid)[2*(i*theta_sample+j)+1] * sigma_3;
-                        vec3_scale2(tmp_xy, tmp_cst);
-                        vec3_add2(xyz_travel,tmp_xy);
-							
-                        rg_length = beam->rpl_vol->get_rgdepth(xyz_travel);
-                        HU = beam->rpl_ct_vol_HU_lg->get_rgdepth(xyz_travel);
-                        if (beam->get_intersection_with_aperture(idx_ap, idx_ap_int, rest, xyz_travel) == false)
-                        {
-                            continue;
-                        }
 
-                        /* Check that the ray cross the aperture */
-                        if (idx_ap[0] < 0 || idx_ap[0] > (double) beam->rpl_ct_vol_HU->get_proj_volume()->get_image_dim(0)-1
-                            || idx_ap[1] < 0 || idx_ap[1] > (double) beam->rpl_ct_vol_HU->get_proj_volume()->get_image_dim(1)-1)
-                        {
-                            continue;
-                        }
-                        /* Check that the ray cross the active part of the aperture */
-                        if (beam->get_aperture()->have_aperture_image() && beam->is_ray_in_the_aperture(idx_ap_int, ap_img) == false)
-                        {
-                            continue;
-                        }
-                        /* Check that the spot map is positive for this ray */
-                        particle_number = beam->get_mebs()->get_particle_number_xyz(idx_ap_int, rest, beam_index, beam->get_aperture()->get_dim());
-                        if (particle_number <= 0)
-                        {
-                            continue;
-                        }
-                        ct_density = compute_density_from_HU(HU);
-                        STPR = compute_PrSTPR_from_HU(HU);
-							
-                        if (rg_length <= 0)
+    /* Save sigma volume */
+    if (beam->get_sigma_out() != "") {
+        std::string fn;
+        fn = string_format ("%s/cax-%02d",
+            beam->get_sigma_out().c_str(), energy_index);
+        cax_dose_rv->save (fn);
+        fn = string_format ("%s/sig-%02d", 
+            beam->get_sigma_out().c_str(), energy_index);
+        sigma_rv->save (fn);
+    }
+    
+    // Smear dose by specified sigma
+    for (int s = 0; s < num_steps; s++) {
+        double pixel_spacing[2] = {
+            lateral_spacing_0[s],
+            lateral_spacing_1[s]
+        };
+        for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) {
+            for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) {
+                plm_long idx = s*sigma_dim[0]*sigma_dim[1] + ij[1]*dim[0] + ij[0];
+                float cax_dose = cax_dose_img[idx];
+                if (cax_dose == 0.f) {
+                    continue;
+                }
+                double sigma = (double) sigma_img[idx];
+                double sigma_x3 = sigma * 2.5;
+                
+                // finding the rpl_volume pixels that are contained in the
+                // the 3 sigma range
+                plm_long ij_min[2], ij_max[2];
+                ij_min[0] = ij[0] - ceil (sigma_x3 / lateral_spacing_0[s]);
+                if (ij_min[0] < 0) ij_min[0] = 0;
+                ij_min[1] = ij[1] - ceil (sigma_x3 / lateral_spacing_1[s]);
+                if (ij_min[1] < 0) ij_min[1] = 0;
+                ij_max[0] = ij[0] + ceil (sigma_x3 / lateral_spacing_0[s]);
+                if (ij_max[0] > dim[0]-1) ij_max[0] = dim[0]-1;
+                ij_max[1] = ij[1] + ceil (sigma_x3 / lateral_spacing_1[s]);
+                if (ij_max[1] > dim[1]-1) ij_max[1] = dim[1]-1;
+
+                float tot_off_axis = 0.f;
+                plm_long ij1[2];
+                for (ij1[1] = ij_min[1]; ij1[1] <= ij_max[1]; ij1[1]++) {
+                    for (ij1[0] = ij_min[0]; ij1[0] <= ij_max[0]; ij1[0]++) {
+                        plm_long idxs = s*sigma_dim[0]*sigma_dim[1]
+                            + ij1[1]*dim[0] + ij1[0];
+                        double gaussian_center[2] = { 0., 0. };
+                        double pixel_center[2] = {
+                            (double) ij1[0]-ij[0],
+                            (double) ij1[1]-ij[1]
+                        };
+                        double off_axis_factor;
+                        if (sigma == 0)
                         {
-                            continue;
+                            off_axis_factor = 1;
                         }
                         else
                         {
-		
-                            /* the dose from that sector is summed */
-                            sigma_travel = beam->sigma_vol->get_rgdepth(xyz_travel);
-                            radius = vec3_dist(xyz, xyz_travel);
-								
-                            if (sigma_travel < radius / 3)
-                            {
-                                continue;
-                            }
-                            else
-                            {
-                                central_sector_dose = particle_number * beam->get_mebs()->get_depth_dose()[beam_index]->lookup_energy_integration((float) rg_length, ct_density * beam->rpl_vol->get_vol()->spacing[2])* STPR * (1/(sigma_travel*sqrt(2*M_PI)));
-                                dr = sigma_3 / (2* radius_sample);
-                                dose_img[idx] +=  
-                                    central_sector_dose
-                                    * compute_PrWER_from_HU(HU)
-                                    * get_off_axis(radius, dr, sigma_3/3) 
-                                    * beam->get_mebs()->get_weight()[beam_index]; 
-                            }
+                            off_axis_factor = double_gaussian_interpolation (
+                                gaussian_center, pixel_center,
+                                sigma, pixel_spacing);
                         }
+
+                        dose_rv_img[idxs] += cax_dose * off_axis_factor;
+#if defined (commentout)
+                        // GCS FIX: The below correction would give the
+                        // option for dose to tissue
+                        / ct_density / STPR;
+#endif
+                        tot_off_axis += off_axis_factor;
                     }
                 }
             }
         }
     }
+
+    // Free temporary memory
+    delete cax_dose_rv;
+    beam->get_rt_dose_timing()->timer_dose_calc.stop ();
 }
 
-void add_rcomp_length_to_rpl_volume (Rt_beam* beam)
+void
+add_rcomp_length_to_rpl_volume (Rt_beam* beam)
 {
-    const plm_long *dim = beam->rpl_vol->get_vol()->dim;
-    float* rpl_img = (float*) beam->rpl_vol->get_vol()->img;
-    float* rc_img = (float*) beam->rpl_vol->get_aperture()->get_range_compensator_volume()->img;
+    const plm_long *dim = beam->rsp_accum_vol->get_vol()->dim;
+    float* rpl_img = (float*) beam->rsp_accum_vol->get_vol()->img;
+    float* rc_img = (float*) beam->rsp_accum_vol->get_aperture()->get_range_compensator_volume()->img;
     int idx = 0;
 
     for(int i = 0; i < dim[0] * dim[1]; i++)
diff --git a/src/plastimatch/dose/rt_dose.h b/src/plastimatch/dose/rt_dose.h
old mode 100644
new mode 100755
index ceac39a..9fdb6a6
--- a/src/plastimatch/dose/rt_dose.h
+++ b/src/plastimatch/dose/rt_dose.h
@@ -17,6 +17,32 @@ energy_direct (
 	int beam_idx
 );
 
+void compute_dose_a (
+    Volume::Pointer dose_vol, 
+    Rt_beam* beam, 
+    const Volume::Pointer ct_vol
+);
+void compute_dose_b (
+    Rt_beam* beam,
+    size_t energy_index,
+    const Volume::Pointer ct_vol
+);
+void compute_dose_ray_trace_dij_a (
+    Rt_beam* beam,
+    size_t energy_index,
+    const Volume::Pointer ct_vol,
+    Volume::Pointer& dose_vol
+);
+void compute_dose_ray_trace_dij_b (
+    Rt_beam* beam,
+    const Volume::Pointer ct_vol,
+    Volume::Pointer& dose_vol
+);
+void compute_dose_d (
+    Rt_beam* beam,
+    size_t energy_index,
+    const Volume::Pointer ct_vol
+);
 void compute_dose_ray_desplanques (
     Volume* dose_volume, 
     Volume::Pointer ct_vol, 
@@ -28,7 +54,7 @@ void compute_dose_ray_sharp (
     const Volume::Pointer ct_vol,  
     Rt_beam* beam,
     Rpl_volume* rpl_dose_volume,
-	int beam_index,
+    int beam_index,
     const int* margins
 );
 void compute_dose_ray_shackleford (
diff --git a/src/plastimatch/dose/rt_dose_timing.h b/src/plastimatch/dose/rt_dose_timing.h
new file mode 100644
index 0000000..d6f3333
--- /dev/null
+++ b/src/plastimatch/dose/rt_dose_timing.h
@@ -0,0 +1,39 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _rt_dose_timing_h_
+#define _rt_dose_timing_h_
+
+#include "plmdose_config.h"
+#include "logfile.h"
+#include "plm_timer.h"
+#include "smart_pointer.h"
+
+class Rt_dose_timing
+{
+public:
+    SMART_POINTER_SUPPORT (Rt_dose_timing);
+public:
+    Plm_timer timer_sigma;
+    Plm_timer timer_dose_calc;
+    Plm_timer timer_reformat;
+    Plm_timer timer_io;
+    Plm_timer timer_misc;
+public:
+    void reset () {
+        timer_sigma.reset ();
+        timer_dose_calc.reset ();
+        timer_reformat.reset ();
+        timer_io.reset ();
+        timer_misc.reset ();
+    }
+    void report () {
+        lprintf ("Sigma:     %f seconds\n", timer_sigma.report());
+        lprintf ("Calc:      %f seconds\n", timer_dose_calc.report());
+        lprintf ("IO:        %f seconds\n", timer_io.report());
+        lprintf ("Reformat:  %f seconds\n", timer_reformat.report());
+        lprintf ("Misc:      %f seconds\n", timer_misc.report());
+    };
+};
+
+#endif
diff --git a/src/plastimatch/dose/rt_lut.cxx b/src/plastimatch/dose/rt_lut.cxx
index c9676a7..4ad6183 100644
--- a/src/plastimatch/dose/rt_lut.cxx
+++ b/src/plastimatch/dose/rt_lut.cxx
@@ -76,36 +76,36 @@ double get_proton_stop (double energy)
 
 double get_theta0_Highland(double range)
 {
-	/* lucite sigma0 (in rads) computing- From the figure A2 of the Hong's paper (be careful, in this paper the fit shows sigma0^2)*/
-	if (range > 150)
-	{
-		return 0.05464 + 5.8348E-6 * range -5.21006E-9 * range * range;
-	}
-	else 
-	{
-		return 0.05394 + 1.80222E-5 * range -5.5430E-8 * range * range;
-	}
+    /* lucite sigma0 (in rads) computing- From the figure A2 of the Hong's paper (be careful, in this paper the fit shows sigma0^2)*/
+    if (range > 150)
+    {
+        return 0.05464 + 5.8348E-6 * range -5.21006E-9 * range * range;
+    }
+    else 
+    {
+        return 0.05394 + 1.80222E-5 * range -5.5430E-8 * range * range;
+    }
 }
 
 double get_theta0_MC(float energy)
 {
-	return 4.742E-6 * energy * energy -1.918E-3 * energy + 1.158;
+    return 4.742E-6 * energy * energy -1.918E-3 * energy + 1.158;
 }
 
 double get_theta_rel_Highland(double rc_over_range)
 {
-	return rc_over_range * ( 1.6047 -2.7295 * rc_over_range + 2.1578 * rc_over_range * rc_over_range);
+    return rc_over_range * ( 1.6047 -2.7295 * rc_over_range + 2.1578 * rc_over_range * rc_over_range);
 }
 
 double get_theta_rel_MC(double rc_over_range)
 {
-	return 3.833E-2 * pow(rc_over_range, 0.657) + 2.118E-2 * pow(rc_over_range, 6.528);
+    return 3.833E-2 * pow(rc_over_range, 0.657) + 2.118E-2 * pow(rc_over_range, 6.528);
 }
 
 double get_scat_or_Highland(double rc_over_range)
 {
-	/* calculation of rc_eff - see Hong's paper graph A3 - linear interpolation of the curve */
-	if (rc_over_range >= 0 && rc_over_range < 0.5)
+    /* calculation of rc_eff - see Hong's paper graph A3 - linear interpolation of the curve */
+    if (rc_over_range >= 0 && rc_over_range < 0.5)
     {
         return 1 - (0.49 + 0.060 / 0.5 * rc_over_range);
     }
@@ -135,12 +135,14 @@ double get_scat_or_Highland(double rc_over_range)
     }
 }
 
-double get_scat_or_MC(double rc_over_range)
+double
+get_scat_or_MC (double rc_over_range)
 {
-	return 0.023 * rc_over_range + 0.332;
+    return 0.023 * rc_over_range + 0.332;
 }
 
-double compute_X0_from_HU(double CT_HU)
+double
+compute_X0_from_HU (double CT_HU)
 {
     if (CT_HU <= -1000)
     {
diff --git a/src/plastimatch/dose/rt_mebs.cxx b/src/plastimatch/dose/rt_mebs.cxx
old mode 100644
new mode 100755
index 24ee137..3dcb0c8
--- a/src/plastimatch/dose/rt_mebs.cxx
+++ b/src/plastimatch/dose/rt_mebs.cxx
@@ -41,9 +41,10 @@ public:
     float proximal_margin;
     float distal_margin;
 
-    double spread; /* spread for optimized SOBP, may be changed to a vector for each energy */
+    /* spread for optimized SOBP, may be changed to a vector for each energy */
+    double spread;
 
-    /* p  & alpha are parameters that bind depth and energy 
+    /* p & alpha are parameters that bind depth and energy 
        according to ICRU */
     Particle_type particle_type;			
     double alpha;
@@ -75,6 +76,9 @@ public:
     std::string particle_number_in;
     std::string particle_number_out;
 
+    /* debug */
+    bool debug;
+    
 public:
     Rt_mebs_private ()
     {
@@ -88,9 +92,9 @@ public:
         this->energy_res = 1.f;
         this->energy_number = 1;
 
-        this->target_min_depth = 0.f;			/* lower depth  of target */
-        this->target_max_depth = 0.f;			/* higher depth of target */
-        this->depth_res = 0.01f;				/* depth resolution */
+        this->target_min_depth = 0.f;		/* lower depth  of target */
+        this->target_max_depth = 0.f;		/* higher depth of target */
+        this->depth_res = 0.01f;		/* depth resolution */
         this->depth_end = 20.f;
 
         this->prescription_depth_min = 0.f;
@@ -113,6 +117,8 @@ public:
 
         this->particle_number_in ="";
         this->particle_number_out ="";
+
+        this->debug = false;
     }
     Rt_mebs_private (Particle_type part)
     {
@@ -126,9 +132,9 @@ public:
         this->energy_res = 1.f;
         this->energy_number = 1;
 
-        this->target_min_depth = 0.f;			/* lower depth  of target */
-        this->target_max_depth = 0.f;			/* higher depth of target */
-        this->depth_res = 0.01f;				/* depth resolution */
+        this->target_min_depth = 0.f;
+        this->target_max_depth = 0.f;
+        this->depth_res = 0.01f;
         this->depth_end = 20.f;
 
         this->prescription_depth_min = 0.f;
@@ -162,9 +168,9 @@ public:
         this->energy_res = rsp->energy_res;
         this->energy_number = rsp->energy_number;
 
-        this->target_min_depth = rsp->target_min_depth;	/* lower depth  of target */
-        this->target_max_depth = rsp->target_max_depth;	/* higher depth of target */
-        this->depth_res = rsp->depth_res;				/* depth resolution */
+        this->target_min_depth = rsp->target_min_depth;
+        this->target_max_depth = rsp->target_max_depth;
+        this->depth_res = rsp->depth_res;
         this->depth_end = rsp->depth_end;
 
         this->prescription_depth_min = rsp->prescription_depth_min;
@@ -189,19 +195,19 @@ public:
         this->particle_number_out = rsp->particle_number_out;
 
         /* copy the associated depth dose and update the dept dose curve */
-        for (int i = 0; i < rsp->depth_dose.size(); i++)
+        for (size_t i = 0; i < rsp->depth_dose.size(); i++)
         {
             this->depth_dose.push_back(rsp->depth_dose[i]);
         }
-        for (int i = 0; i < rsp->depth_dose_weight.size(); i++)
+        for (size_t i = 0; i < rsp->depth_dose_weight.size(); i++)
         {
             this->depth_dose_weight.push_back(rsp->depth_dose_weight[i]);
         }
-        for (int i = 0; i < rsp->energies.size(); i++)
+        for (size_t i = 0; i < rsp->energies.size(); i++)
         {
             this->energies.push_back(rsp->energies[i]);
         }
-        for (int i = 0; i < rsp->num_particles.size(); i++)
+        for (size_t i = 0; i < rsp->num_particles.size(); i++)
         {
             this->num_particles.push_back(rsp->num_particles[i]);
         }
@@ -220,7 +226,10 @@ public:
             this->e_lut[i] = rsp->e_lut[i];
             this->f_lut[i] = rsp->f_lut[i];
         }
+
+        this->debug = false;
     }
+public:
     ~Rt_mebs_private ()
     {
         if (d_lut) delete[] d_lut;
@@ -308,7 +317,6 @@ public:
             num_particles.pop_back();
         }
     }
-	
 };
 
 Rt_mebs::Rt_mebs ()
@@ -356,8 +364,7 @@ Rt_mebs::add_depth_dose (Rt_depth_dose* depth_dose)
     d_ptr->energies.push_back(depth_dose->E0);
 
     /* update the mebs depth dose length if this one is longer */
-    if (depth_dose->num_samples > d_ptr->num_samples)
-    {
+    if (depth_dose->num_samples > d_ptr->num_samples) {
         d_ptr->num_samples = depth_dose->num_samples;
     }
 }
@@ -389,8 +396,7 @@ Rt_mebs::add_peak (double E0, double spread, double weight)
         d_ptr->energies.push_back(E0);
 
         /* update the mebs depth dose length if this one is longer */
-        if (depth_dose->num_samples > d_ptr->num_samples)
-        {
+        if (depth_dose->num_samples > d_ptr->num_samples) {
             d_ptr->num_samples = depth_dose->num_samples;
         }
     }
@@ -469,7 +475,7 @@ Rt_mebs::lookup_energy (
             * ((d_ptr->e_lut[i+1] - d_ptr->e_lut[i]) 
                 / (d_ptr->d_lut[i+1] - d_ptr->d_lut[i]));
     } else {
-        // we wen't past the end of the lookup table
+        // we went past the end of the lookup table
         energy = 0.0f;
     }
     return energy;
@@ -494,7 +500,7 @@ Rt_mebs::generate ()
         d_ptr->f_lut[i] = 0;
     }
 
-    for (int it = 0; it < d_ptr->depth_dose.size(); it++)
+    for (size_t it = 0; it < d_ptr->depth_dose.size(); it++)
     {
         const Rt_depth_dose *ppp = d_ptr->depth_dose[it];
         /* Check that this peak has the same resolution */
@@ -529,7 +535,7 @@ Rt_mebs::dump (const char* dir)
 
     /* Dump SOBP */
     std::string sobp_fn = string_format ("%s/bragg_curve.txt", dir);
-    FILE* fp = fopen (sobp_fn.c_str(), "w");
+    FILE* fp = plm_fopen (sobp_fn.c_str(), "w");
     for (int i=0; i < d_ptr->num_samples; i++) {
         fprintf (fp, "%3.2f %3.2f\n", d_ptr->d_lut[i], d_ptr->e_lut[i]);
     }
@@ -553,12 +559,12 @@ Rt_mebs::printparameters()
     printf ("\nParticle type : %s, alpha: %lg, p: %lg\n", particle_type_string (d_ptr->particle_type), d_ptr->alpha, d_ptr->p);
     printf("Number of depth_dose : %d\n",d_ptr->energy_number = d_ptr->depth_dose.size());
     printf("Energy set (in MeV):\n");
-    for (int i = 0; i < d_ptr->energies.size(); i++)
+    for (size_t i = 0; i < d_ptr->energies.size(); i++)
     {
         printf("%lg ", d_ptr->energies[i]);
     }
     printf("\nweights set:\n");
-    for (int i = 0; i < d_ptr->depth_dose_weight.size(); i++)
+    for (size_t i = 0; i < d_ptr->depth_dose_weight.size(); i++)
     {
         printf("%lg ", d_ptr->depth_dose_weight[i]);
     }
@@ -659,8 +665,8 @@ Rt_mebs::set_target_depths(float new_depth_min, float new_depth_max)
 void 
 Rt_mebs::set_target_depths(float new_z_min, float new_z_max, float new_step)
 {
-	d_ptr->depth_res = new_step;
-	this->set_target_depths(new_z_min, new_z_max);
+    d_ptr->depth_res = new_step;
+    this->set_target_depths(new_z_min, new_z_max);
 }
 
 void 
@@ -1040,10 +1046,10 @@ Rt_mebs::get_num_particles()
 }
 
 void
-Rt_mebs::set_prescription(float prescription_min, float prescription_max)
+Rt_mebs::set_prescription (float prescription_min, float prescription_max)
 {
     d_ptr->have_prescription = true;
-    this->set_prescription_depths(prescription_min, prescription_max);
+    this->set_prescription_depths (prescription_min, prescription_max);
 }
 
 void 
@@ -1218,7 +1224,7 @@ Rt_mebs::optimize_sobp ()
     std::vector<float> energy_tmp;
     this->optimizer (&weight_tmp, &energy_tmp);
 
-    for (int i = 0; i < energy_tmp.size(); i++)
+    for (size_t i = 0; i < energy_tmp.size(); i++)
     {
         add_peak(energy_tmp[i], d_ptr->spread, weight_tmp[i]);
     }
@@ -1235,7 +1241,10 @@ Rt_mebs::optimizer (std::vector<float>* weight_tmp, std::vector<float>* energy_t
 }
 
 void
-Rt_mebs::initialize_energy_weight_and_depth_dose_vectors(std::vector<float>* weight_tmp, std::vector<float>* energy_tmp, std::vector<Rt_depth_dose*>* depth_dose_tmp)
+Rt_mebs::initialize_energy_weight_and_depth_dose_vectors (
+    std::vector<float>* weight_tmp,
+    std::vector<float>* energy_tmp,
+    std::vector<Rt_depth_dose*>* depth_dose_tmp)
 {
     /* initialize the energies in the table */
     printf("\n %d Mono-energetic BP used:\n", d_ptr->energy_number);
@@ -1249,7 +1258,7 @@ Rt_mebs::initialize_energy_weight_and_depth_dose_vectors(std::vector<float>* wei
             d_ptr->energy_number--;
             (*energy_tmp).pop_back();
             weight_tmp->pop_back();
-            printf("sobp: peak with energy < 0, Energy resolution error. Last peak deleted.\n");
+            printf ("sobp: peak with energy < 0, Energy resolution error. Last peak deleted.\n");
         }
     }
     printf("\n");
@@ -1268,14 +1277,12 @@ Rt_mebs::initialize_energy_weight_and_depth_dose_vectors(std::vector<float>* wei
 }
 
 void 
-Rt_mebs::generate_part_num_from_weight(int* ap_dim)
+Rt_mebs::generate_part_num_from_weight (const plm_long* ap_dim)
 {
     //int idx = 0;
-    for (int i = 0; i < d_ptr->energy_number; i++)
-    {
-        for (int j = 0; j < ap_dim[0] * ap_dim[1]; j++)
-        {
-            d_ptr->num_particles.push_back(d_ptr->depth_dose_weight[i]);
+    for (int i = 0; i < d_ptr->energy_number; i++) {
+        for (int j = 0; j < ap_dim[0] * ap_dim[1]; j++) {
+            d_ptr->num_particles.push_back (d_ptr->depth_dose_weight[i]);
         }
     }
 }
@@ -1290,27 +1297,53 @@ Rt_mebs::scale_num_part(double A, int* ap_dim)
 }
 
 double 
-Rt_mebs::get_particle_number_xyz(int* idx, double* rest, int idx_beam, const int* ap_dim)
+Rt_mebs::get_particle_number_xyz (
+    plm_long* idx, double* rest, int dd_idx, const plm_long* ap_dim)
 {
-    /* The boundaries possible errors like idx = dim are already excluded by the test on the aperture
-       Practically, idx = dim -1 is not possible */
+    /* The boundaries possible errors like idx = dim are already excluded by 
+       the test on the aperture. Practically, idx = dim -1 is not possible */
     double A = 0;
     double B = 0;
-    int spot = 0;
-    spot = ap_dim[0] * ap_dim[1] * idx_beam + ap_dim[0] * idx[1] + idx[0];
-    A = d_ptr->num_particles[spot] + rest[0] * ( d_ptr->num_particles[spot+1] -  d_ptr->num_particles[spot]);
-    spot = ap_dim[0] * ap_dim[1] * idx_beam + ap_dim[0] * (idx[1] +1 ) + idx[0];
-    B =  d_ptr->num_particles[spot] + rest[0] * ( d_ptr->num_particles[spot+1] -  d_ptr->num_particles[spot]);
+    int beamlet = 0;
+    beamlet = ap_dim[0] * ap_dim[1] * dd_idx + ap_dim[0] * idx[1] + idx[0];
+    A = d_ptr->num_particles[beamlet] + rest[0] * ( d_ptr->num_particles[beamlet+1] -  d_ptr->num_particles[beamlet]);
+#if defined (commentout)
+    if (d_ptr->debug) {
+        printf (" Mebs::GPNXYZ %f %f",
+            d_ptr->num_particles[beamlet],
+            d_ptr->num_particles[beamlet+1]
+        );
+    }
+#endif
+    beamlet = ap_dim[0] * ap_dim[1] * dd_idx + ap_dim[0] * (idx[1]+1) + idx[0];
+    B =  d_ptr->num_particles[beamlet] + rest[0] * ( d_ptr->num_particles[beamlet+1] -  d_ptr->num_particles[beamlet]);
+#if defined (commentout)
+    if (d_ptr->debug) {
+        printf (" %f %f\n",
+            d_ptr->num_particles[beamlet],
+            d_ptr->num_particles[beamlet+1]
+        );
+    }
+#endif
     return A + rest[1] * (B-A);
 }
 
 void 
-Rt_mebs::extract_particle_number_map_from_txt(Aperture::Pointer& ap)
+Rt_mebs::set_from_spot_map (const Rt_spot_map::Pointer& rsm)
+{
+    this->clear_depth_dose ();
+
+    const std::list<Rt_spot>& spot_list = rsm->get_spot_list();
+
+}
+
+void 
+Rt_mebs::load_beamlet_map (Aperture::Pointer& ap)
 {
     /* Confirm file can be read */
     if (!file_exists (d_ptr->particle_number_in)) {
         printf ("Error reading config file: %s\n", d_ptr->particle_number_in.c_str());
-        printf("Particle number map set to 0 for each dose spot \n");
+        printf("Particle number map set to 0 for each dose beamlet \n");
         return;
     }
 
@@ -1331,7 +1364,7 @@ Rt_mebs::extract_particle_number_map_from_txt(Aperture::Pointer& ap)
     char sep[] = " ";
     char* token;
 
-    int spot_number = 0;
+    int beamlet_number = 0;
     int line_number = 0;
     int energy_number = 0;
     int idx = 0;
@@ -1345,11 +1378,11 @@ Rt_mebs::extract_particle_number_map_from_txt(Aperture::Pointer& ap)
         if (buf == "") continue;
         if (buf[0] == '#') continue;
 
-        /* Check the dim for the last spot map */
+        /* Check the dim for the last beamlet map */
         if (buf.find ("[Energy]") != std::string::npos && energy_number != 0 && line_number != ap->get_dim(1))
         {
-            printf("***WARNING*** the number of spot line doesn't correspond to the aperture size\n");
-            printf("spot line number expected: %d, spot line detected: %d.\n", ap->get_dim(1), line_number);
+            printf("***WARNING*** the number of beamlet line doesn't correspond to the aperture size\n");
+            printf("beamlet line number expected: %d, beamlet line detected: %d.\n", ap->get_dim(1), line_number);
         }
 
         if (buf.find ("[Energy]") != std::string::npos)
@@ -1358,7 +1391,7 @@ Rt_mebs::extract_particle_number_map_from_txt(Aperture::Pointer& ap)
             val = buf.c_str();
             val = strtok(&val[0], "[Energy]");
             energy = strtod(val.c_str(),0);
-            spot_number = 0;
+            beamlet_number = 0;
             line_number = 0;
 
             if (energy > 0)
@@ -1378,74 +1411,77 @@ Rt_mebs::extract_particle_number_map_from_txt(Aperture::Pointer& ap)
             continue;
         }
 
-        /* If we arrive here, it means that we read a spot map */
+        /* If we arrive here, it means that we read a beamlet map */
         val ="";
         val = buf.c_str();
         val = string_trim (val);
 					
         token = strtok(&val[0], sep);
-        spot_number = 0;
+        beamlet_number = 0;
 
         while (token != NULL)
         {
             part_number = strtod(token,0);
-            if (spot_number < ap->get_dim(0))
+            if (beamlet_number < ap->get_dim(0))
             {
-                idx = (energy_number-1) * ap->get_dim(0) * ap->get_dim(1) + line_number * ap->get_dim(0) + spot_number;
+                idx = (energy_number-1) * ap->get_dim(0) * ap->get_dim(1) + line_number * ap->get_dim(0) + beamlet_number;
                 d_ptr->num_particles[idx] = part_number;
-                spot_number++;
+                beamlet_number++;
             }
             token = strtok(NULL, sep);
         }
-        if (spot_number != ap->get_dim(0))
+        if (beamlet_number != ap->get_dim(0))
         {
-            printf("***WARNING*** the number of spots doesn't correspond to the aperture size\n");
-            printf("line %d: spot number expected: %d, spot number detected: %d.\n", line_number, ap->get_dim(0), spot_number);
+            printf("***WARNING*** the number of beamlets doesn't correspond to the aperture size\n");
+            printf("line %d: beamlet number expected: %d, beamlet number detected: %d.\n", line_number, ap->get_dim(0), beamlet_number);
         }
         line_number++;
     }
 
-    /* Check the dim for the last spot map */
+    /* Check the dim for the last beamlet map */
     if (energy_number != 0 && line_number != ap->get_dim(1))
     {
-        printf("***WARNING*** the number of spot line doesn't correspond to the aperture size\n");
-        printf("spot line number expected: %d, spot line detected: %d.\n", ap->get_dim(1), line_number);
+        printf("***WARNING*** the number of beamlet line doesn't correspond to the aperture size\n");
+        printf("beamlet line number expected: %d, beamlet line detected: %d.\n", ap->get_dim(1), line_number);
     }
 }
 
 void
-Rt_mebs::compute_particle_number_matrix_from_target_active (Rpl_volume* rpl_vol, Plm_image::Pointer& target, float smearing)
+Rt_mebs::compute_particle_number_matrix_from_target_active (
+    Rpl_volume* rpl_vol,
+    std::vector <double>& wepl_min,
+    std::vector <double>& wepl_max)
 {
-    int dim[2] = {rpl_vol->get_aperture()->get_dim()[0], rpl_vol->get_aperture()->get_dim()[1]};
+    int dim[2] = {
+        rpl_vol->get_aperture()->get_dim()[0],
+        rpl_vol->get_aperture()->get_dim()[1]
+    };
 
     /* vector containing the min and the max of depth of the target */
-    std::vector <double> dmin;
-    std::vector <double> dmax;
     float min = 0;
     float max = 0;
-    rpl_vol->compute_beam_modifiers_active_scanning(target->get_vol(), smearing, d_ptr->proximal_margin, d_ptr->distal_margin, dmin, dmax);
 
     /* Sanity check */
-    if (dmin.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1) 
-        || dmax.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1))
+    if (wepl_min.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1) 
+        || wepl_max.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1))
     {
         printf("ERROR: the aperture size doesn't correspond to the min and max depth maps of the target.\n");
-        printf("Aperture size: %d, min depth map size: %d, max depth map size: %d.\n", rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1), dmin.size(), dmax.size());
+        printf("Aperture size: %d, min depth map size: %d, max depth map size: %d.\n", rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1), (int) wepl_min.size(), (int) wepl_max.size());
     }
 
-    for (int i = 0; i < dmax.size(); i++)
+    for (size_t i = 0; i < wepl_max.size(); i++)
     {
-        if (dmax[i] > max)
+        if (wepl_max[i] > max)
         {
-            max = dmax[i];
+            max = wepl_max[i];
         }
     }
     min = max;
-    for (int i = 0; i < dmin.size(); i++)
+    for (size_t i = 0; i < wepl_min.size(); i++)
     {
-        if (dmin[i] < min && dmin[i] != 0)
+        if (wepl_min[i] < min && wepl_min[i] != 0)
         {
-            min = dmin[i];
+            min = wepl_min[i];
         }
     }
     this->set_prescription_depths(min, max);
@@ -1455,19 +1491,20 @@ Rt_mebs::compute_particle_number_matrix_from_target_active (Rpl_volume* rpl_vol,
     std::vector<float> energy_tmp;
     std::vector<float> weight_tmp;
     std::vector<Rt_depth_dose*> depth_dose_tmp;
-    this->initialize_energy_weight_and_depth_dose_vectors(&weight_tmp, &energy_tmp, &depth_dose_tmp);
+    this->initialize_energy_weight_and_depth_dose_vectors (&weight_tmp, &energy_tmp, &depth_dose_tmp);
 
     /* initialization of the dose matrix slice for monoenergetic slice */
-    for (int i = 0; i < dim[0] *  dim[1] * d_ptr->energy_number;i++)
+    for (int i = 0; i < dim[0] *  dim[1] * d_ptr->energy_number; i++)
     {
         d_ptr->num_particles.push_back(0);
     }
 
     printf("Optimization of the particle number map for any mono-energetic slice in progress...\n");
     /* Let's optimize the SOBP for each beamlet */
-    for (int i = 0; i < dmin.size(); i++)
+    for (size_t i = 0; i < wepl_min.size(); i++)
     {
-        this->get_optimized_peaks(dmin[i], dmax[i], &weight_tmp, &depth_dose_tmp);
+        this->get_optimized_peaks (wepl_min[i], wepl_max[i],
+            &weight_tmp, &depth_dose_tmp);
         for (int j = 0; j < d_ptr->energy_number; j++)
         {
             d_ptr->num_particles[i + j *  dim[0] *  dim[1] ] = weight_tmp[j];
@@ -1475,87 +1512,23 @@ Rt_mebs::compute_particle_number_matrix_from_target_active (Rpl_volume* rpl_vol,
             weight_tmp[j] = 0;
         }
     }
-    for (int i = 0; i < energy_tmp.size(); i++)
+    for (size_t i = 0; i < energy_tmp.size(); i++)
     {
         add_peak(energy_tmp[i], d_ptr->spread, 1);
     }
 }
 
-void
-Rt_mebs::compute_particle_number_matrix_from_target_active_slicerRt (Rpl_volume* rpl_vol, Plm_image::Pointer& target, float smearing)
-{
-    int dim[2] = {rpl_vol->get_aperture()->get_dim()[0], rpl_vol->get_aperture()->get_dim()[1]};
-
-    /* vector containing the min and the max of depth of the target */
-    std::vector <double> dmin;
-    std::vector <double> dmax;
-    float min = 0;
-    float max = 0;
-    rpl_vol->compute_beam_modifiers_core_slicerRt(target, true, smearing, d_ptr->proximal_margin, d_ptr->distal_margin, dmin, dmax);
-
-    /* Sanity check */
-    if (dmin.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1) 
-        || dmax.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1))
-    {
-        printf("ERROR: the aperture size doesn't correspond to the min and max depth maps of the target.\n");
-        printf("Aperture size: %d, min depth map size: %d, max depth map size: %d.\n", rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1), dmin.size(), dmax.size());
-    }
-
-    for (int i = 0; i < dmax.size(); i++)
-    {
-        if (dmax[i] > max)
-        {
-            max = dmax[i];
-        }
-    }
-    min = max;
-    for (int i = 0; i < dmin.size(); i++)
-    {
-        if (dmin[i] < min && dmin[i] != 0)
-        {
-            min = dmin[i];
-        }
-    }
-    this->set_prescription_depths(min, max);
-    printf("Min and max depths in the PTV (target + margins): %lg mm and %lg mm.\n", d_ptr->prescription_depth_min, d_ptr->prescription_depth_max);
-    printf("Min and max energies for treating the PTV: %lg MeV and %lg MeV.\n", d_ptr->beam_min_energy, d_ptr->beam_max_energy);
-
-    std::vector<float> energy_tmp;
-    std::vector<float> weight_tmp;
-    std::vector<Rt_depth_dose*> depth_dose_tmp;
-    this->initialize_energy_weight_and_depth_dose_vectors(&weight_tmp, &energy_tmp, &depth_dose_tmp);
-
-    /* initialization of the dose matrix slice for monoenergetic slice */
-    for (int i = 0; i < dim[0] *  dim[1] * d_ptr->energy_number;i++)
-    {
-        d_ptr->num_particles.push_back(0);
-    }
-
-    printf("Optimization of the particle number map for any mono-energetic slice in progress...\n");
-    /* Let's optimize the SOBP for each beamlet */
-    for (int i = 0; i < dmin.size(); i++)
-    {
-        this->get_optimized_peaks(dmin[i], dmax[i], &weight_tmp, &depth_dose_tmp);
-        for (int j = 0; j < d_ptr->energy_number; j++)
-        {
-            d_ptr->num_particles[i + j *  dim[0] *  dim[1] ] = weight_tmp[j];
-            /* Reset weight_tmp for next turn */
-            weight_tmp[j] = 0;
-        }
-    }
-    for (int i = 0; i < energy_tmp.size(); i++)
-    {
-        add_peak(energy_tmp[i], d_ptr->spread, 1);
-    }
-}
-
-/* This function returns optimized weighted peaks for passive systems (SOBP weights)
-	and active systems (beamlet particle numbers for each energy) */
+/* This function returns optimized weighted peaks for passive systems 
+   (SOBP weights) and active systems (beamlet particle numbers 
+   for each energy) */
 void 
-Rt_mebs::get_optimized_peaks(float dmin, float dmax, std::vector<float>* weight_tmp, std::vector<Rt_depth_dose*>* depth_dose_tmp)
+Rt_mebs::get_optimized_peaks (
+    float dmin,
+    float dmax,
+    std::vector<float>* weight_tmp,
+    std::vector<Rt_depth_dose*>* depth_dose_tmp)
 {
-    if (dmin == 0 || dmax == 0)
-    {
+    if (dmin == 0 || dmax == 0) {
         return;
     }
     int energy_min_index = (int) floor(pow((dmin/(10*d_ptr->alpha)),(1/d_ptr->p)) / d_ptr->energy_res);
@@ -1565,10 +1538,12 @@ Rt_mebs::get_optimized_peaks(float dmin, float dmax, std::vector<float>* weight_
     float E_max_sobp = (float) energy_max_index * d_ptr->energy_res;
 
     /* This is useful only for active scanning */
-    /* check that the E_max is sufficiently high for covering the distal part of the prescription */
+    /* check that the E_max is sufficiently high for covering the distal 
+       part of the prescription */
     E_max_sobp += this->check_and_correct_max_energy(E_max_sobp, dmax);
 
-    /* check that the E_min is sufficiently low for covering the distal part of the prescription */
+    /* check that the E_min is sufficiently low for covering the distal 
+       part of the prescription */
     E_min_sobp += this->check_and_correct_min_energy(E_min_sobp, dmin);
 
     int i0 = (int) ((d_ptr->beam_max_energy - E_max_sobp) / d_ptr->energy_res);
@@ -1583,7 +1558,6 @@ Rt_mebs::get_optimized_peaks(float dmin, float dmax, std::vector<float>* weight_
     }
 
     int idx_max = 0;
-
     for (int i = i0; i <= imax; i++)
     {
         idx_max = (*depth_dose_tmp)[i]->index_of_dose_max;
@@ -1610,7 +1584,8 @@ Rt_mebs::get_optimized_peaks(float dmin, float dmax, std::vector<float>* weight_
             e_lut_tmp[j] += (*weight_tmp)[i] *  (*depth_dose_tmp)[i]->e_lut[j];
         }
     }
-    
+
+    /* Repeat for 40 iterations */
     for (int k = 0; k < 40; k++)
     {
         for (int i = i0; i <= imax; i++)
@@ -1651,23 +1626,23 @@ Rt_mebs::get_optimized_peaks(float dmin, float dmax, std::vector<float>* weight_
         return;
     }
 
-    for(int i = i0; i <= imax; i++)
+    for (int i = i0; i <= imax; i++)
     {
         (*weight_tmp)[i] /= (float) (mean_sobp / mean_count);
     }
 }
 
 void 
-Rt_mebs::export_spot_map_as_txt(Aperture::Pointer ap)
+Rt_mebs::export_as_txt(Aperture::Pointer ap)
 {
     make_parent_directories (d_ptr->particle_number_out.c_str());
 	
-    printf("Trying to write spot maps in %s\n", d_ptr->particle_number_out.c_str());
+    printf("Trying to write mebs in %s\n", d_ptr->particle_number_out.c_str());
 
     std::ofstream fichier(d_ptr->particle_number_out.c_str());
 
     if ( !fichier ){
-        std::cerr << "Erreur de creation du fichier spot_map" << std::endl;
+        std::cerr << "Erreur de creation du fichier beamlet_map" << std::endl;
         return;
     }
 
@@ -1690,3 +1665,8 @@ Rt_mebs::export_spot_map_as_txt(Aperture::Pointer ap)
     fichier.close();
 }
 
+void
+Rt_mebs::set_debug (bool debug)
+{
+    d_ptr->debug = debug;
+}
diff --git a/src/plastimatch/dose/rt_mebs.h b/src/plastimatch/dose/rt_mebs.h
old mode 100644
new mode 100755
index ce3c183..cf9500f
--- a/src/plastimatch/dose/rt_mebs.h
+++ b/src/plastimatch/dose/rt_mebs.h
@@ -2,8 +2,9 @@
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
 /* -----------------------------------------------------------------------
-   rt_mebs (for mono-energetic_beam_set) is a class that creates beams of different energies,
-   including SOBP (Spread Out Bragg Peak) or any multi-energy beam configuration. 
+   rt_mebs (for mono-energetic beamlet set) is a class that creates beams 
+   of different energies, including SOBP (Spread Out Bragg Peak) 
+   or any multi-energy beam configuration. 
    ----------------------------------------------------------------------- */
 #ifndef _rt_mebs_h_
 #define _rt_mebs_h_
@@ -18,6 +19,7 @@
 #include "plm_config.h"
 #include "rpl_volume.h"
 #include "rt_lut.h"
+#include "rt_spot_map.h"
 #include "smart_pointer.h"
 
 class Rt_depth_dose;
@@ -131,22 +133,41 @@ public:
     /* Optimize, then generate mebs depth curve from prescription 
        range and modulation */
     void optimize_sobp ();
-    /* Weight optimizer */
-    void optimizer (std::vector<float>* weight_tmp, std::vector<float>* energy_tmp);
 
-    void get_optimized_peaks(float dmin, float dmax, std::vector<float>* weight_tmp, std::vector<Rt_depth_dose*>* depth_dose);
-    void initialize_energy_weight_and_depth_dose_vectors(std::vector<float>* weight_tmp, std::vector<float>* energy_tmp, std::vector<Rt_depth_dose*>* depth_dose_tmp);
+    /* Weight optimizer */
+    void optimizer (std::vector<float>* weight_tmp, 
+        std::vector<float>* energy_tmp);
+    void get_optimized_peaks (float dmin, float dmax, 
+        std::vector<float>* weight_tmp, 
+        std::vector<Rt_depth_dose*>* depth_dose);
+    void initialize_energy_weight_and_depth_dose_vectors (
+        std::vector<float>* weight_tmp, std::vector<float>* energy_tmp, 
+        std::vector<Rt_depth_dose*>* depth_dose_tmp);
+
+    void scale_num_part (double A, int* ap_dim);
+    double get_particle_number_xyz (plm_long* idx, double* rest, 
+        int idx_beam, const plm_long* ap_dim);
+
+    // returns also the wed max and min maps
+    void compute_beam_modifiers_active_scanning (
+        Volume *seg_vol, float smearing, 
+        float proximal_margin, float distal_margin, 
+        std::vector<double>& map_wed_min, std::vector<double>& map_wed_max);
+    
+    /* This computes the E_min and E_max map from a target for all pencil beam*/
+    void generate_part_num_from_weight (const plm_long* ap_dim);
+    void compute_particle_number_matrix_from_target_active (
+        Rpl_volume* rpl_vol,
+        std::vector <double>& wepl_min,
+        std::vector <double>& wepl_max);
 
-    void scale_num_part(double A, int* ap_dim);
-    double get_particle_number_xyz(int* idx, double* rest, int idx_beam, const int* ap_dim);
+    void set_from_spot_map (const Rt_spot_map::Pointer& rsm);
 
-    /* This computes the E_min and E_max map from a target for all pencil beam*/
-    void generate_part_num_from_weight(int* ap_dim);
-    void extract_particle_number_map_from_txt(Aperture::Pointer& ap);
-    void compute_particle_number_matrix_from_target_active(Rpl_volume* rpl_vol, Plm_image::Pointer& target, float smearing);
-    void compute_particle_number_matrix_from_target_active_slicerRt (Rpl_volume* rpl_vol, Plm_image::Pointer& target, float smearing);
+    void load_beamlet_map (Aperture::Pointer& ap);
+    void export_as_txt (Aperture::Pointer ap);
 
-    void export_spot_map_as_txt(Aperture::Pointer ap);
+    /* Debugging */
+    void set_debug (bool);
 };
 
 #endif
diff --git a/src/plastimatch/dose/rt_parms.cxx b/src/plastimatch/dose/rt_parms.cxx
old mode 100644
new mode 100755
index 79850b1..08e41a2
--- a/src/plastimatch/dose/rt_parms.cxx
+++ b/src/plastimatch/dose/rt_parms.cxx
@@ -135,9 +135,10 @@ public:
     virtual Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key,
+        const std::string& index, 
         const std::string& val)
     {
-        return this->rp->set_key_value (section, key, val);
+        return this->rp->set_key_value (section, key, index, val);
     }
 };
 
@@ -168,6 +169,7 @@ Plm_return_code
 Rt_parms::set_key_value (
     const std::string& section,
     const std::string& key, 
+    const std::string& index, 
     const std::string& val)
 {
     if (section == "COMMENT" || section == "GLOBAL") {
@@ -181,7 +183,7 @@ Rt_parms::set_key_value (
         }
         else if (key == "target") {
             d_ptr->rt_plan->set_target (val);
-         }
+        }
         else if (key == "threading") {
             Threading threading = THREADING_CPU_OPENMP;
             if (val == "single") {
@@ -209,7 +211,10 @@ Rt_parms::set_key_value (
             d_ptr->rt_plan->set_threading (threading);
         }
         else if (key == "dose_out") {
-            d_ptr->rt_plan->set_output_dose (val);
+            d_ptr->rt_plan->set_output_dose_fn (val);
+        }
+        else if (key == "psp_out") {
+            d_ptr->rt_plan->set_output_psp_fn (val);
         }
         else if (key == "debug") {
             d_ptr->rt_plan->set_debug (string_value_true (val));
@@ -219,13 +224,13 @@ Rt_parms::set_key_value (
             if (sscanf (val.c_str(), "%f", &norm_dose) != 1) {
                 goto error_exit;
             }
-			if (norm_dose <= 0) {
-				goto error_exit;
-			}
+            if (norm_dose <= 0) {
+                goto error_exit;
+            }
             d_ptr->rt_plan->set_normalization_dose (norm_dose);
-			d_ptr->rt_plan->set_have_dose_norm(true);
+            d_ptr->rt_plan->set_have_dose_norm(true);
         }
-		else if (key == "ref_dose_point") {
+        else if (key == "ref_dose_point") {
             float rdp[3];
             int rc = sscanf (val.c_str(), "%f %f %f", 
                 &rdp[0], &rdp[1], &rdp[2]);
@@ -233,9 +238,9 @@ Rt_parms::set_key_value (
                 goto error_exit;
             }
             d_ptr->rt_plan->set_ref_dose_point (rdp);
-			d_ptr->rt_plan->set_have_ref_dose_point(true);
+            d_ptr->rt_plan->set_have_ref_dose_point(true);
         }
-		else if (key == "non_normalized_dose") {
+        else if (key == "non_normalized_dose") {
             if (val.length() >= 1) {
                 d_ptr->rt_plan->set_non_norm_dose (val[0]);
             } else {
@@ -254,12 +259,12 @@ Rt_parms::set_key_value (
 
         if (key == "flavor") {
             if (val.length() >= 1) {
-                rt_beam->set_flavor (val[0]);
+                rt_beam->set_flavor (val);
             } else {
                 goto error_exit;
             } 
         }
-		else if (key == "beam_line") {
+        else if (key == "beam_line") {
             rt_beam->set_beam_line_type (val);
         }
         else if (key == "homo_approx") {
@@ -285,10 +290,13 @@ Rt_parms::set_key_value (
         else if (key == "proj_img_out") {
             rt_beam->set_proj_img_out (val);
         }
+        else if (key == "proj_target_out") {
+            rt_beam->set_proj_target_out (val);
+        }
         else if (key == "rc_out") {
             rt_beam->set_range_compensator_out (val);
         }
-		else if (key == "particle_number_out") {
+        else if (key == "particle_number_out") {
             rt_beam->get_mebs()->set_particle_number_out (val);
         }
         else if (key == "sigma_out") {
@@ -297,6 +305,12 @@ Rt_parms::set_key_value (
         else if (key == "wed_out") {
             rt_beam->set_wed_out (val);
         }
+        else if (key == "beam_dump_out") {
+            rt_beam->set_beam_dump_out (val);
+        }
+        else if (key == "dij_out") {
+            rt_beam->set_dij_out (val);
+        }
         else if (key == "beam_type") {
             Particle_type part = particle_type_parse (val);
             if (part == PARTICLE_TYPE_UNKNOWN) {
@@ -315,13 +329,13 @@ Rt_parms::set_key_value (
             if (sscanf (val.c_str(), "%lf", &(d_ptr->max_depth)) != 1) {
                 goto error_exit;
             }
-			rt_beam->get_mebs()->set_depth_end(d_ptr->max_depth);
+            rt_beam->get_mebs()->set_depth_end(d_ptr->max_depth);
         }
         else if (key == "depth_dose_z_res") {
             if (sscanf (val.c_str(), "%lf", &(d_ptr->depth_res)) != 1) {
                 goto error_exit;
             }
-			rt_beam->get_mebs()->set_depth_resolution(d_ptr->max_depth);
+            rt_beam->get_mebs()->set_depth_resolution(d_ptr->max_depth);
         }
         else if (key == "source") {
             float src[3];
@@ -343,7 +357,7 @@ Rt_parms::set_key_value (
         }
         else if (key == "prescription_min_max") {
             float prescription_min;
-			float prescription_max;
+            float prescription_max;
             int rc = sscanf (val.c_str(), "%f %f", &prescription_min, &prescription_max);
             if (rc != 2) {
                 goto error_exit;
@@ -376,11 +390,12 @@ Rt_parms::set_key_value (
             rt_beam->set_aperture_origin (ap_origin);
         }
         else if (key == "aperture_resolution") {
-            int ap_dim[2];
-            int rc = sscanf (val.c_str(), "%i %i", &ap_dim[0], &ap_dim[1]);
+            int a, b;
+            int rc = sscanf (val.c_str(), "%i %i", &a, &b);
             if (rc != 2) {
                 goto error_exit;
             }
+            plm_long ap_dim[2] = { a, b };
             rt_beam->set_aperture_resolution (ap_dim);
         }
         else if (key == "aperture_spacing") {
@@ -392,7 +407,7 @@ Rt_parms::set_key_value (
             }
             rt_beam->set_aperture_spacing (ap_spacing);
         }
-		else if (key == "range_comp_mc_model") {
+        else if (key == "range_comp_mc_model") {
             if (val.length() >= 1) {
                 rt_beam->set_rc_MC_model (val[0]);
             } else {
@@ -412,9 +427,9 @@ Rt_parms::set_key_value (
         else if (key == "range_compensator_file_in") {
             rt_beam->set_range_compensator_in (val);
         }
-		else if (key == "particle_number_in") {
+        else if (key == "particle_number_in") {
             rt_beam->get_mebs()->set_particle_number_in (val);
-			rt_beam->get_mebs()->set_have_particle_number_map(true);
+            rt_beam->get_mebs()->set_have_particle_number_map(true);
         }
         else if (key == "aperture_smearing") {
             float smearing;
@@ -437,7 +452,7 @@ Rt_parms::set_key_value (
             }
             rt_beam->get_mebs()->set_distal_margin (distal_margin);
         }
-		else if (key == "energy_resolution") {
+        else if (key == "energy_resolution") {
             float eres;
             if (sscanf (val.c_str(), "%f", &eres) != 1) {
                 goto error_exit;
@@ -451,6 +466,14 @@ Rt_parms::set_key_value (
             }
             rt_beam->get_mebs()->set_photon_energy (photon_energy);
         }
+        else if (key == "spot") {
+            float xpos, ypos, energy, sigma, weight;
+            if (sscanf (val.c_str(), "%f,%f,%f,%f,%f", 
+                    &xpos, &ypos, &energy, &sigma, &weight) != 1) {
+                goto error_exit;
+            }
+            rt_beam->add_spot (xpos, ypos, energy, sigma, weight);
+        }
         else {
             goto error_exit;
         }
@@ -487,13 +510,20 @@ Rt_parms::set_key_value (
     print_and_exit ("Unknown section value: %s\n", section.c_str());
     return PLM_ERROR;
 
-	error_exit:
+error_exit:
     print_and_exit ("Unknown (key,val) combination: (%s,%s)\n", 
         key.c_str(), val.c_str());
     return PLM_ERROR;
 }
 
 Plm_return_code
+Rt_parms::set_command_file (const char *command_file)
+{
+    Rt_parms_parser rpp (this);
+    return rpp.parse_config_file (command_file);
+}
+
+Plm_return_code
 Rt_parms::parse_args (int argc, char** argv)
 {
     int i;
@@ -512,6 +542,6 @@ Rt_parms::parse_args (int argc, char** argv)
     if (!argv[i]) {
         print_usage ();
     }
-    Rt_parms_parser rpp (this);
-    return rpp.parse_config_file (argv[i]);
+
+    return this->set_command_file (argv[i]);
 }
diff --git a/src/plastimatch/dose/rt_parms.h b/src/plastimatch/dose/rt_parms.h
index f5f6637..209f331 100644
--- a/src/plastimatch/dose/rt_parms.h
+++ b/src/plastimatch/dose/rt_parms.h
@@ -27,15 +27,18 @@ public:
 
 public:
     void set_rt_plan (Rt_plan *rt_plan);
+    Plm_return_code set_command_file (const char *command_file);
     Plm_return_code parse_args (int argc, char** argv);
     Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key, 
+        const std::string& index, 
         const std::string& val);
 
     void append_beam ();
     void append_peak ();
 
+
 protected:
     void parse_config (const char* config_fn);
 };
diff --git a/src/plastimatch/dose/rt_plan.cxx b/src/plastimatch/dose/rt_plan.cxx
old mode 100644
new mode 100755
index dc4d613..415603d
--- a/src/plastimatch/dose/rt_plan.cxx
+++ b/src/plastimatch/dose/rt_plan.cxx
@@ -8,6 +8,7 @@
 
 #include "aperture.h"
 #include "dose_volume_functions.h"
+#include "float_pair_list.h"
 #include "plm_image.h"
 #include "plm_exception.h"
 #include "plm_timer.h"
@@ -17,8 +18,10 @@
 #include "ray_data.h"
 #include "rpl_volume.h"
 #include "rt_beam.h"
+#include "rt_beam_model.h"
 #include "rt_depth_dose.h"
 #include "rt_dose.h"
+#include "rt_dose_timing.h"
 #include "rt_lut.h"
 #include "rt_parms.h"
 #include "rt_plan.h"
@@ -26,9 +29,10 @@
 #include "rt_mebs.h"
 #include "rt_study.h"
 #include "volume.h"
+#include "volume_adjust.h"
+#include "volume_header.h"
 #include "volume_macros.h"
-
-static void display_progress (float is, float of);
+#include "volume_resample.h"
 
 class Rt_plan_private {
 
@@ -45,16 +49,21 @@ public:
     std::string patient_fn;
     std::string target_fn;
     std::string output_dose_fn;
-    std::string output_proj_img_fn;
+    std::string output_psp_fn;
 
-    /* Patient (ct_image) , target, output dose volume */
-    Plm_image::Pointer patient;
+    /* Patient (hu), patient (ed or sp) , target, output dose volume */
+    Plm_image::Pointer patient_hu;
+    Plm_image::Pointer patient_psp;
     Plm_image::Pointer target;
     Plm_image::Pointer dose;
 
     Rt_parms::Pointer rt_parms;
     Rt_study* rt_study;
 
+    Rt_dose_timing::Pointer rt_dose_timing;
+
+    Rt_beam_model::Pointer beam_model;
+
     /* Storage of beams */
     std::vector<Rt_beam*> beam_storage;
 
@@ -71,10 +80,12 @@ public:
         this->non_norm_dose = 'n';
         this->depth_dose_max = 1.f;
         
-        patient = Plm_image::New();
-        target = Plm_image::New();
+        patient_hu = Plm_image::New();
+        patient_psp = Plm_image::Pointer();
+        target = Plm_image::Pointer();
         dose = Plm_image::New();
         rt_parms = Rt_parms::New ();
+        rt_dose_timing = Rt_dose_timing::New ();
     }
 
     ~Rt_plan_private ()
@@ -85,6 +96,7 @@ public:
 Rt_plan::Rt_plan ()
 {
     this->d_ptr = new Rt_plan_private;
+    d_ptr->rt_parms->set_rt_plan (this);
 }
 
 Rt_plan::~Rt_plan ()
@@ -95,10 +107,15 @@ Rt_plan::~Rt_plan ()
 Plm_return_code
 Rt_plan::parse_args (int argc, char* argv[])
 {
-    d_ptr->rt_parms->set_rt_plan (this);
     return d_ptr->rt_parms->parse_args (argc, argv);
 }
 
+Plm_return_code
+Rt_plan::set_command_file (const char *command_file)
+{
+    return d_ptr->rt_parms->set_command_file (command_file);
+}
+
 void
 Rt_plan::set_patient (const std::string& patient_fn)
 {
@@ -108,58 +125,67 @@ Rt_plan::set_patient (const std::string& patient_fn)
 void
 Rt_plan::set_patient (Plm_image::Pointer& ct_vol)
 {
-    d_ptr->patient = ct_vol;
+    d_ptr->patient_hu = ct_vol;
+    d_ptr->patient_hu->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
+    d_ptr->patient_psp = Plm_image::Pointer ();
 }
 
 void
 Rt_plan::set_patient (ShortImageType::Pointer& ct_vol)
 {
-    d_ptr->patient->set_itk (ct_vol);
-
-    /* compute_segdepth_volume assumes float */
-    d_ptr->patient->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
+    /* compute_segdepth_volume assumes float, so convert here */
+    d_ptr->patient_hu->set_itk (ct_vol);
+    d_ptr->patient_hu->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
+    d_ptr->patient_psp = Plm_image::Pointer ();
 }
 
 void
 Rt_plan::set_patient (FloatImageType::Pointer& ct_vol)
 {
-    d_ptr->patient->set_itk (ct_vol);
+    d_ptr->patient_hu->set_itk (ct_vol);
+    d_ptr->patient_hu->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
+    d_ptr->patient_psp = Plm_image::Pointer ();
 }
 
 void
 Rt_plan::set_patient (Volume* ct_vol)
 {
-    d_ptr->patient->set_volume (ct_vol);
+    d_ptr->patient_hu->set_volume (ct_vol);
 }
 
 Volume::Pointer
 Rt_plan::get_patient_volume ()
 {
-    return d_ptr->patient->get_volume_float ();
+    return d_ptr->patient_hu->get_volume_float ();
 }
 
 Plm_image *
 Rt_plan::get_patient ()
 {
-    return d_ptr->patient.get();
+    return d_ptr->patient_hu.get();
 }
 
 void
 Rt_plan::set_target (const std::string& target_fn)
 {
     d_ptr->target_fn = target_fn;
-    d_ptr->target = Plm_image::New (new Plm_image (target_fn));
+}
 
-    /* Need float, because compute_segdepth_volume assumes float */
+void
+Rt_plan::set_target (UCharImageType::Pointer& target_vol)
+{
+    d_ptr->target = Plm_image::New (target_vol);
+
+    /* compute_segdepth_volume assumes float */
     d_ptr->target->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
 
     this->propagate_target_to_beams ();
 }
 
 void
-Rt_plan::set_target (UCharImageType::Pointer& target_vol)
+Rt_plan::set_target (FloatImageType::Pointer& target_vol)
 {
-    d_ptr->target->set_itk (target_vol);
+    d_ptr->target = Plm_image::New (target_vol);
 
     /* compute_segdepth_volume assumes float */
     d_ptr->target->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
@@ -168,9 +194,15 @@ Rt_plan::set_target (UCharImageType::Pointer& target_vol)
 }
 
 void
-Rt_plan::set_target (FloatImageType::Pointer& target_vol)
+Rt_plan::load_target ()
 {
-    d_ptr->target->set_itk (target_vol);
+    if (d_ptr->target_fn == "") {
+        return;
+    }
+    d_ptr->target = Plm_image::New (new Plm_image (d_ptr->target_fn));
+
+    /* Need float, because compute_segdepth_volume assumes float */
+    d_ptr->target->convert (PLM_IMG_TYPE_GPUIT_FLOAT);
 
     this->propagate_target_to_beams ();
 }
@@ -204,6 +236,7 @@ Rt_plan::append_beam ()
         new_beam = new Rt_beam;
     }
     d_ptr->beam_storage.push_back (new_beam);
+    new_beam->set_rt_dose_timing (d_ptr->rt_dose_timing);
     new_beam->set_target (d_ptr->target);
     return new_beam;
 }
@@ -236,7 +269,7 @@ Rt_plan::set_threading (Threading threading)
 }
 
 void
-Rt_plan::set_normalization_dose(float normalization_dose)
+Rt_plan::set_normalization_dose (float normalization_dose)
 {
     d_ptr->normalization_dose = normalization_dose;
 }
@@ -278,25 +311,25 @@ Rt_plan::set_ref_dose_point (const double* rdp)
 void 
 Rt_plan::set_have_ref_dose_point(bool have_rdp)
 {
-	d_ptr->have_rdp = have_rdp;
+    d_ptr->have_rdp = have_rdp;
 }
 
 bool
 Rt_plan::get_have_ref_dose_point()
 {
-	return d_ptr->have_rdp;
+    return d_ptr->have_rdp;
 }
 
 void 
-Rt_plan::set_have_dose_norm(bool have_dose_norm)
+Rt_plan::set_have_dose_norm (bool have_dose_norm)
 {
-	d_ptr->have_dose_norm = have_dose_norm;
+    d_ptr->have_dose_norm = have_dose_norm;
 }
 
 bool
 Rt_plan::get_have_dose_norm()
 {
-	return d_ptr->have_dose_norm;
+    return d_ptr->have_dose_norm;
 }
 
 char 
@@ -308,7 +341,7 @@ Rt_plan::get_non_norm_dose () const
 void 
 Rt_plan::set_non_norm_dose (char non_norm_dose)
 {
-	d_ptr->non_norm_dose = non_norm_dose;
+    d_ptr->non_norm_dose = non_norm_dose;
 }
 
 void
@@ -320,447 +353,221 @@ Rt_plan::propagate_target_to_beams ()
     }
 }
 
-bool
-Rt_plan::prepare_beam_for_calc (Rt_beam *beam)
+void
+Rt_plan::create_patient_psp ()
 {
-    if (!beam) return false;
-    if (!this->get_patient()) return false;
+    Float_pair_list lookup;
+    lookup.push_back (std::pair<float,float> (NLMIN(float), 0));
+    lookup.push_back (std::pair<float,float> (-1000, 0.00106));
+    lookup.push_back (std::pair<float,float> (0, 1.0));
+    lookup.push_back (std::pair<float,float> (41.46, 1.048674));
+    lookup.push_back (std::pair<float,float> (NLMAX(float), 0.005011));
+
+    Volume::Pointer psp = volume_adjust (
+        d_ptr->patient_hu->get_volume(), lookup);
+    d_ptr->patient_psp = Plm_image::New (psp);
+}
 
-    if (beam->get_aperture()->get_distance() > beam->get_source_distance ())
+void
+Rt_plan::normalize_beam_dose (Rt_beam *beam)
+{
+    Plm_image::Pointer dose = beam->get_dose ();
+    Volume::Pointer dose_vol = dose->get_volume ();
+    float* dose_img = (float*) dose_vol->img;
+    
+    /* Dose normalization process*/
+    if (this->get_non_norm_dose() != 'y')
     {
-        throw Plm_exception ("Source distance must be greater than aperture distance");
+        if (this->get_have_ref_dose_point()) // case 1: ref dose point defined
+        {
+            float rdp_ijk[3] = {0,0,0};
+            float rdp[3] = {this->get_ref_dose_point(0), this->get_ref_dose_point(1), this->get_ref_dose_point(2)};
+            rdp_ijk[0] = (rdp[0] - dose_vol->origin[0]) / dose_vol->spacing[0];
+            rdp_ijk[1] = (rdp[1] - dose_vol->origin[1]) / dose_vol->spacing[1];
+            rdp_ijk[2] = (rdp[2] - dose_vol->origin[2]) / dose_vol->spacing[2];
+			
+            if (rdp_ijk[0] >=0 && rdp_ijk[1] >=0 && rdp_ijk[2] >=0 && rdp_ijk[0] < dose_vol->dim[0] && rdp_ijk[1] < dose_vol->dim[1] && rdp_ijk[2] < dose_vol->dim[2])
+            {
+                printf("Dose normalized to the dose reference point.\n");
+                dose_normalization_to_dose_and_point(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), rdp_ijk, rdp, beam); // if no normalization dose, norm_dose = 1 by default
+                if (this->get_have_dose_norm())
+                {
+                    printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose());
+                }
+                else
+                {
+                    printf("%lg x 100%%.\n", beam->get_beam_weight());
+                }
+                printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1));
+            }
+            else
+            {
+                printf("***WARNING***\nThe reference dose point is not in the image volume.\n");
+                dose_normalization_to_dose(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), beam);
+                if (this->get_have_dose_norm())
+                {
+                    printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose());
+                }
+                else
+                {
+                    printf("%lg x 100%%.\n", beam->get_beam_weight());
+                }
+                printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1));
+            }
+        }
+        else // case 2: no red dose point defined
+        {				
+            dose_normalization_to_dose(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), beam); // normalization_dose = 1 if no dose_prescription is set
+            if (this->get_have_dose_norm())
+            {
+                printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose());
+            }
+            else
+            {
+                printf("%lg x 100%%.\n", beam->get_beam_weight());
+            }
+            printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1));
+        }
     }
-    
-    if (!beam->rpl_vol) {beam->rpl_vol = new Rpl_volume;}
-    beam->rpl_vol->set_geometry (
-        beam->get_source_position(),
-        beam->get_isocenter_position(),
-        beam->get_aperture()->vup,
-        beam->get_aperture()->get_distance(),
-        beam->get_aperture()->get_dim(),
-        beam->get_aperture()->get_center(),
-        beam->get_aperture()->get_spacing(),
-        beam->get_step_length());
-    if (!beam->rpl_vol) return false;
-    /* building the ct_density_vol */
-    beam->rpl_ct_vol_HU = new Rpl_volume;
-    beam->rpl_ct_vol_HU->set_geometry (
-        beam->get_source_position(),
-        beam->get_isocenter_position(),
-        beam->get_aperture()->vup,
-        beam->get_aperture()->get_distance(),
-        beam->get_aperture()->get_dim(),
-        beam->get_aperture()->get_center(),
-        beam->get_aperture()->get_spacing(),
-        beam->get_step_length());
-    if (!beam->rpl_ct_vol_HU) return false;
-    if (beam->get_flavor() == 'f'|| beam->get_flavor() == 'g' || beam->get_flavor() == 'h')
+    else // raw dose, dose not normalized
     {
-        /* building the sigma_vol */
-        beam->sigma_vol = new Rpl_volume;
-        beam->sigma_vol->set_geometry (
-            beam->get_source_position(),
-            beam->get_isocenter_position(),
-            beam->get_aperture()->vup,
-            beam->get_aperture()->get_distance(),
-            beam->get_aperture()->get_dim(),
-            beam->get_aperture()->get_center(),
-            beam->get_aperture()->get_spacing(),
-            beam->get_step_length());
-        
-        if (!beam->sigma_vol) return false;
+        for (int i = 0; i < dose_vol->dim[0] * dose_vol->dim[1] * dose_vol->dim[2]; i++)
+        {
+            dose_img[i] *= beam->get_beam_weight();
+        }
     }
+}
+
+void
+Rt_plan::compute_dose (Rt_beam *beam)
+{
+    printf ("-- compute_dose entry --\n");
+    d_ptr->rt_dose_timing->timer_misc.resume ();
+    Volume::Pointer ct_vol = this->get_patient_volume ();
+    Volume::Pointer dose_vol = ct_vol->clone_empty ();
 
-    /* Copy aperture from scene into rpl volume */
-    beam->rpl_ct_vol_HU->set_aperture (beam->get_aperture());
+    Volume* dose_volume_tmp = new Volume;
 
-    beam->rpl_vol->set_aperture (beam->get_aperture());
+    float margin = 0;
+    int margins[2] = {0,0};
+    double range = 0;
+    int new_dim[2]={0,0};
+    double new_center[2]={0,0};
+    double biggest_sigma_ever = 0;
 
-    if (beam->get_flavor() == 'f' || beam->get_flavor() == 'g' || beam->get_flavor() == 'h')
-    {
-        Aperture::Pointer ap_sigma = Aperture::New(beam->get_aperture());
-        beam->sigma_vol->set_aperture (ap_sigma);
-        beam->sigma_vol->set_aperture (beam->get_aperture());
+    /* Convert from HU to stopping power, if not already done */
+    if (!d_ptr->patient_psp) {
+        this->create_patient_psp ();
     }
 
-    /* Scan through aperture to fill in rpl_volume */
-    beam->rpl_vol->set_ct_volume (d_ptr->patient);
-
-    if(beam->rpl_vol->get_ct() && beam->rpl_vol->get_ct_limit())
-    {
-        /* We don't do everything again, we just copy the ct & ct_limits as all the volumes geometrically equal*/
-        beam->rpl_ct_vol_HU->set_ct (beam->rpl_vol->get_ct());
-        beam->rpl_ct_vol_HU->set_ct_limit(beam->rpl_vol->get_ct_limit());
-        
-        if (beam->get_flavor() == 'f' || beam->get_flavor() == 'g' || beam->get_flavor() == 'h')
-        {
-            beam->sigma_vol->set_ct(beam->rpl_vol->get_ct());
-            beam->sigma_vol->set_ct_limit(beam->rpl_vol->get_ct_limit());
-        }
+    /* Resample target to match CT resolution, if not already done */
+    if (d_ptr->target) {
+        Volume_header vh (d_ptr->patient_hu);
+        d_ptr->target->set_volume (
+            volume_resample (d_ptr->target->get_volume(), &vh));
+        this->propagate_target_to_beams ();
     }
-    else
+    d_ptr->rt_dose_timing->timer_misc.stop ();
+    
+    /* Create rpl images, compute beam modifiers, SOBP etc. according 
+       to the teatment strategy */
+    d_ptr->rt_dose_timing->timer_dose_calc.resume ();
+    if (!beam->prepare_for_calc (d_ptr->patient_hu,
+            d_ptr->patient_psp, d_ptr->target))
     {
-        printf("ray_data or clipping planes to be copied from rpl volume don't exist\n");
+        print_and_exit ("ERROR: Unable to initilize plan.\n");
     }
+    d_ptr->rt_dose_timing->timer_dose_calc.stop ();
 
-    /*Now we can compute the rpl_volume*/
-    beam->rpl_vol->compute_rpl_PrSTRP_no_rgc ();
-    /* and the others */
-    if(beam->rpl_vol->get_Ray_data() && beam->rpl_vol->get_front_clipping_plane() && beam->rpl_vol->get_back_clipping_plane())
-    {
-        beam->rpl_ct_vol_HU->set_ray(beam->rpl_vol->get_Ray_data());
-        beam->rpl_ct_vol_HU->set_front_clipping_plane(beam->rpl_vol->get_front_clipping_plane());
-        beam->rpl_ct_vol_HU->set_back_clipping_plane(beam->rpl_vol->get_back_clipping_plane());
-        beam->rpl_ct_vol_HU->compute_rpl_HU();
+#if defined (commentout)
+    printf ("Computing rpl_ct\n");
+    beam->hu_samp_vol->compute_rpl_HU ();
+#endif
+    
+    if (beam->get_flavor() == "a") {
+        compute_dose_a (dose_vol, beam, ct_vol);
+    }
+    else if (beam->get_flavor() == "b") {
+
+        d_ptr->rt_dose_timing->timer_dose_calc.resume ();
 
-        if (beam->get_flavor() == 'f' || beam->get_flavor() == 'g' || beam->get_flavor() == 'h')
+        // Add range compensator to rpl volume
+        if (beam->rsp_accum_vol->get_aperture()->have_range_compensator_image())
         {
-            /* We don't do everything again, we just copy the ray_data & clipping planes as all the volumes geometrically equal*/
+            add_rcomp_length_to_rpl_volume(beam);
+        }
         
-            beam->sigma_vol->set_ray(beam->rpl_vol->get_Ray_data());
-            beam->sigma_vol->set_front_clipping_plane(beam->rpl_vol->get_front_clipping_plane());
-            beam->sigma_vol->set_back_clipping_plane(beam->rpl_vol->get_back_clipping_plane());
+        // Loop through energies
+        Rt_mebs::Pointer mebs = beam->get_mebs();
+        std::vector<Rt_depth_dose*> depth_dose = mebs->get_depth_dose();
+        for (size_t i = 0; i < depth_dose.size(); i++) {
+            compute_dose_b (beam, i, ct_vol);
         }
+        d_ptr->rt_dose_timing->timer_dose_calc.stop ();
+        d_ptr->rt_dose_timing->timer_reformat.resume ();
+        dose_volume_reconstruction (beam->dose_rv, dose_vol);
+        d_ptr->rt_dose_timing->timer_reformat.stop ();
     }
-    else
+    else if (beam->get_flavor() == "ray_trace_dij_a")
     {
-        printf("ct or ct_limits to be copied from rpl_vol don't exist\n");
+        /* This is the same as alg 'a', except that it computes 
+           and exports Dij matrices */
+        d_ptr->rt_dose_timing->timer_dose_calc.resume ();
+        // Loop through energies
+        Rt_mebs::Pointer mebs = beam->get_mebs();
+        std::vector<Rt_depth_dose*> depth_dose = mebs->get_depth_dose();
+        for (size_t i = 0; i < depth_dose.size(); i++) {
+            compute_dose_ray_trace_dij_a (beam, i, ct_vol, dose_vol);
+        }
+        d_ptr->rt_dose_timing->timer_dose_calc.resume ();
     }
-    return true;
-}
-
-    void
-        Rt_plan::compute_dose (Rt_beam *beam)
+    else if (beam->get_flavor() == "ray_trace_dij_b")
     {
-        printf ("-- compute_dose entry --\n");
-        Volume::Pointer ct_vol = this->get_patient_volume ();
-        Volume::Pointer dose_vol = ct_vol->clone_empty ();
-        float* dose_img = (float*) dose_vol->img;
-
-        Volume* dose_volume_tmp = new Volume;
-        float* dose_img_tmp = (float*) dose_volume_tmp->img;
-
-        UNUSED_VARIABLE (dose_img_tmp);
-
-        float margin = 0;
-        int margins[2] = {0,0};
-        double range = 0;
-        int new_dim[2]={0,0};
-        double new_center[2]={0,0};
-        double biggest_sigma_ever = 0;
-        Plm_timer timer;
-        double time_sigma_conv = 0.0;
-        double time_dose_calc = 0.0;
-        double time_dose_misc = 0.0;
-        double time_dose_reformat = 0.0;
-
-        printf ("Computing rpl_ct\n");
-        beam->rpl_ct_vol_HU->compute_rpl_HU ();
-
-        if (beam->get_flavor() == 'f' || beam->get_flavor() == 'g' || beam->get_flavor() == 'h')
-        {
-            float sigmaMax = 0;
-            float *sigma_max =&sigmaMax; // used to find the max sigma in the volume and add extra margins during the dose creation volume
-
-            printf ("Computing_void_rpl\n");
-
-            beam->sigma_vol->compute_rpl_PrSTRP_no_rgc(); // we compute the rglength in the sigma_volume, without the range compensator as it will be added by a different process
-            Rpl_volume* sigma_vol = beam->sigma_vol;
-
-            float* sigma_img = (float*) sigma_vol->get_vol()->img;
-            UNUSED_VARIABLE (sigma_img);
-
-
-            /* building the sigma_dose_vol */
-            if (beam->get_flavor() == 'g') {
-                beam->rpl_dose_vol = new Rpl_volume;
-            }
-
-            if (beam->get_flavor() == 'h') {
-                beam->rpl_vol_lg = new Rpl_volume;
-                beam->rpl_ct_vol_HU_lg = new Rpl_volume;
-                beam->sigma_vol_lg = new Rpl_volume;
-            }
+        /* This is the same as alg 'b', except that it computes 
+           and exports Dij matrices */
 
-            printf ("More setup\n");
+        d_ptr->rt_dose_timing->timer_dose_calc.resume ();
 
-            std::vector<Rt_depth_dose*> depth_dose = beam->get_mebs()->get_depth_dose();
-
-            for (size_t i = 0; i < depth_dose.size(); i++) {
-                const Rt_depth_dose *ppp = beam->get_mebs()->get_depth_dose()[i];
-                printf("Building dose matrix for %lg MeV beamlets - \n", ppp->E0);
-                timer.start ();
-
-                compute_sigmas (this, beam, ppp->E0, sigma_max, "small", margins);
-                time_sigma_conv += timer.report ();
-
-                if (beam->get_flavor() == 'f') // Desplanques' algorithm
-                {
-                    range = 10 * get_proton_range(ppp->E0); // range in mm
-                    dose_volume_create(dose_volume_tmp, sigma_max, beam->rpl_vol, range);
-                    compute_dose_ray_desplanques(dose_volume_tmp, ct_vol, beam, dose_vol, i);
-                }
-                else if (beam->get_flavor() == 'g') // Sharp's algorithm
-                {
-                    timer.start ();
-
-                    if (*sigma_max > biggest_sigma_ever)
-                    {
-                        biggest_sigma_ever = *sigma_max;
-                        /* Calculating the pixel-margins of the aperture to take into account the scattering*/
-                        margin = (float) 3 * (*sigma_max)/(beam->get_aperture()->get_distance() + beam->rpl_vol->get_front_clipping_plane()) * beam->get_aperture()->get_distance()+1;
-                        margins[0] = ceil (margin/vec3_len(beam->rpl_vol->get_proj_volume()->get_incr_c()));
-                        margins[1] = ceil (margin/vec3_len(beam->rpl_vol->get_proj_volume()->get_incr_r()));
-                        new_dim[0] = beam->rpl_vol->get_aperture()->get_dim(0) + 2 * margins[0];
-                        new_dim[1] = beam->rpl_vol->get_aperture()->get_dim(1) + 2 * margins[1];
-                        new_center[0] = beam->rpl_vol->get_aperture()->get_center(0) + margins[0];
-                        new_center[1] = beam->rpl_vol->get_aperture()->get_center(1) + margins[1];
-
-                        beam->rpl_dose_vol->get_aperture()->set_center(new_center);
-                        beam->rpl_dose_vol->get_aperture()->set_dim(new_dim);
-                        beam->rpl_dose_vol->get_aperture()->set_distance(beam->rpl_vol->get_aperture()->get_distance());
-                        beam->rpl_dose_vol->get_aperture()->set_spacing(beam->rpl_vol->get_aperture()->get_spacing());
-
-                        beam->rpl_dose_vol->set_geometry (
-                            beam->get_source_position(),
-                            beam->get_isocenter_position(),
-                            beam->get_aperture()->vup,
-                            beam->get_aperture()->get_distance(),
-                            beam->rpl_dose_vol->get_aperture()->get_dim(),
-                            beam->rpl_dose_vol->get_aperture()->get_center(),
-                            beam->get_aperture()->get_spacing(),
-                            beam->get_step_length());
-
-                        beam->rpl_dose_vol->set_ct(beam->rpl_vol->get_ct());
-                        beam->rpl_dose_vol->set_ct_limit(beam->rpl_vol->get_ct_limit());
-                        beam->rpl_dose_vol->compute_ray_data();
-                        beam->rpl_dose_vol->set_front_clipping_plane(beam->rpl_vol->get_front_clipping_plane());
-                        beam->rpl_dose_vol->set_back_clipping_plane(beam->rpl_vol->get_back_clipping_plane());
-                    }
-
-                    /* update the dose_vol with the CT values before to calculate the dose */
-                    beam->rpl_dose_vol->compute_rpl_void();
-                    time_dose_misc += timer.report ();
-
-                    /* dose calculation in the rpl_dose_volume */
-                    timer.start ();
-                    compute_dose_ray_sharp (ct_vol, beam, beam->rpl_dose_vol, i, margins);
-                    time_dose_calc += timer.report ();
-                    timer.start ();
-                    dose_volume_reconstruction(beam->rpl_dose_vol, dose_vol);
-                    time_dose_reformat += timer.report ();
-                }
-
-                if (beam->get_flavor() == 'h') // Shackleford's algorithm
-                {
-                    /* Calculating the pixel-margins of the aperture to take into account the scattering*/
-                    margin = (float) 3 * (*sigma_max)/(beam->get_aperture()->get_distance()+beam->rpl_vol->get_front_clipping_plane()) * beam->get_aperture()->get_distance()+1;
-                    margins[0] = ceil (margin/vec3_len(beam->rpl_vol->get_proj_volume()->get_incr_c()));
-                    margins[1] = ceil (margin/vec3_len(beam->rpl_vol->get_proj_volume()->get_incr_r()));
-                    new_dim[0] = beam->rpl_vol->get_aperture()->get_dim(0) + 2 * margins[0];
-                    new_dim[1] = beam->rpl_vol->get_aperture()->get_dim(1) + 2 * margins[1];
-                    new_center[0] = beam->rpl_vol->get_aperture()->get_center(0) + margins[0];
-                    new_center[1] = beam->rpl_vol->get_aperture()->get_center(1) + margins[1];
-
-                    int radius_sample = 4;
-                    int theta_sample = 8;
-                    std::vector<double> xy_grid (2*(radius_sample * theta_sample),0); // contains the xy coordinates of the sectors in the plane; the central pixel is not included in this vector. 
-                    std::vector<double> area (radius_sample, 0); // contains the areas of the sectors
-
-                    beam->rpl_vol_lg->get_aperture()->set_center(new_center);
-                    beam->rpl_vol_lg->get_aperture()->set_dim(new_dim);
-                    beam->rpl_vol_lg->get_aperture()->set_distance(beam->rpl_vol->get_aperture()->get_distance());
-                    beam->rpl_vol_lg->get_aperture()->set_spacing(beam->rpl_vol->get_aperture()->get_spacing());
-                    beam->rpl_vol_lg->set_geometry (beam->get_source_position(), beam->get_isocenter_position(), beam->get_aperture()->vup, beam->get_aperture()->get_distance(), beam->rpl_vol_lg->get_aperture()->get_dim(), beam->rpl_vol_lg->get_aperture()->get_center(), beam->get_aperture()->get_spacing(), beam->get_step_length());
-                    beam->rpl_vol_lg->set_ct(beam->rpl_vol->get_ct());
-                    beam->rpl_vol_lg->set_ct_limit(beam->rpl_vol->get_ct_limit());
-                    beam->rpl_vol_lg->compute_ray_data();
-                    beam->rpl_vol_lg->compute_rpl_PrSTRP_no_rgc();
-
-                    beam->rpl_ct_vol_HU_lg->get_aperture()->set_center(new_center);
-                    beam->rpl_ct_vol_HU_lg->get_aperture()->set_dim(new_dim);
-                    beam->rpl_ct_vol_HU_lg->get_aperture()->set_distance(beam->rpl_vol->get_aperture()->get_distance());
-                    beam->rpl_ct_vol_HU_lg->get_aperture()->set_spacing(beam->rpl_vol->get_aperture()->get_spacing());
-                    beam->rpl_ct_vol_HU_lg->set_geometry (beam->get_source_position(), beam->get_isocenter_position(), beam->get_aperture()->vup, beam->get_aperture()->get_distance(), beam->rpl_vol_lg->get_aperture()->get_dim(), beam->rpl_vol_lg->get_aperture()->get_center(), beam->get_aperture()->get_spacing(), beam->get_step_length());
-                    beam->rpl_ct_vol_HU_lg->set_ct(beam->rpl_vol->get_ct());
-                    beam->rpl_ct_vol_HU_lg->set_ct_limit(beam->rpl_vol->get_ct_limit());
-                    beam->rpl_ct_vol_HU_lg->compute_ray_data();
-                    beam->rpl_ct_vol_HU_lg->set_front_clipping_plane(beam->rpl_vol_lg->get_front_clipping_plane());
-                    beam->rpl_ct_vol_HU_lg->set_back_clipping_plane(beam->rpl_vol_lg->get_back_clipping_plane());
-                    beam->rpl_ct_vol_HU_lg->compute_rpl_HU();
-
-                    beam->sigma_vol_lg->get_aperture()->set_center(new_center);
-                    beam->sigma_vol_lg->get_aperture()->set_dim(new_dim);	
-                    beam->sigma_vol_lg->get_aperture()->set_distance(beam->rpl_vol->get_aperture()->get_distance());
-                    beam->sigma_vol_lg->get_aperture()->set_spacing(beam->rpl_vol->get_aperture()->get_spacing());
-                    beam->sigma_vol_lg->set_geometry (beam->get_source_position(), beam->get_isocenter_position(), beam->get_aperture()->vup, beam->get_aperture()->get_distance(), beam->rpl_vol_lg->get_aperture()->get_dim(), beam->rpl_vol_lg->get_aperture()->get_center(), beam->get_aperture()->get_spacing(), beam->get_step_length());
-                    beam->sigma_vol_lg->set_ct(beam->rpl_vol->get_ct());
-                    beam->sigma_vol_lg->set_ct_limit(beam->rpl_vol->get_ct_limit());
-                    beam->sigma_vol_lg->compute_ray_data();
-                    beam->sigma_vol_lg->set_front_clipping_plane(beam->rpl_vol_lg->get_front_clipping_plane());
-                    beam->sigma_vol_lg->set_back_clipping_plane(beam->rpl_vol_lg->get_back_clipping_plane());
-                    beam->sigma_vol_lg->compute_rpl_PrSTRP_no_rgc();
-
-                    compute_sigmas (this, beam, ppp->E0, sigma_max, "large", margins);				
-                    build_hong_grid(&area, &xy_grid, radius_sample, theta_sample);
-                    compute_dose_ray_shackleford (
-                        dose_vol, this, beam,
-                        i, &area, &xy_grid,
-                        radius_sample, theta_sample);
-                }
-                printf("dose computed\n");
-            }
-        }
-        if (beam->get_flavor() == 'a') // pull algorithm
-        {    
-            /* Dose D(POI) = Dose(z_POI) but z_POI =  rg_comp + depth in CT, if there is a range compensator */
-            if (beam->rpl_vol->get_aperture()->have_range_compensator_image())
-            {
-                add_rcomp_length_to_rpl_volume(beam);
-            }
-
-            /* scan through patient CT Volume */
-            plm_long ct_ijk[3];
-            double ct_xyz[4];
-            plm_long idx = 0;
-            double idx_ap[2] = {0,0};
-            int idx_ap_int[2] = {0,0};
-            double rest[2] = {0,0};
-            unsigned char* ap_img = (unsigned char*) beam->get_aperture()->get_aperture_volume()->img;
-            double particle_number = 0;
-            float WER = 0;
-            float rgdepth = 0;
-
-            for (ct_ijk[2] = 0; ct_ijk[2] < ct_vol->dim[2]; ct_ijk[2]++) {
-                for (ct_ijk[1] = 0; ct_ijk[1] < ct_vol->dim[1]; ct_ijk[1]++) {
-                    for (ct_ijk[0] = 0; ct_ijk[0] < ct_vol->dim[0]; ct_ijk[0]++) {
-                        double dose = 0.0;
-
-                        /* Transform vol index into space coords */
-                        ct_xyz[0] = (double) (ct_vol->origin[0] + ct_ijk[0] * ct_vol->spacing[0]);
-                        ct_xyz[1] = (double) (ct_vol->origin[1] + ct_ijk[1] * ct_vol->spacing[1]);
-                        ct_xyz[2] = (double) (ct_vol->origin[2] + ct_ijk[2] * ct_vol->spacing[2]);
-                        ct_xyz[3] = (double) 1.0;
-
-                        if (beam->get_intersection_with_aperture(idx_ap, idx_ap_int, rest, ct_xyz) == false)
-                        {
-                            continue;
-                        }
-
-                        /* Check that the ray cross the aperture */
-                        if (idx_ap[0] < 0 || idx_ap[0] > (double) beam->rpl_ct_vol_HU->get_proj_volume()->get_image_dim(0)-1
-                            || idx_ap[1] < 0 || idx_ap[1] > (double) beam->rpl_ct_vol_HU->get_proj_volume()->get_image_dim(1)-1)
-                        {
-                            continue;
-                        }
-
-                        /* Check that the ray cross the active part of the aperture */
-                        if (beam->get_aperture()->have_aperture_image() && beam->is_ray_in_the_aperture(idx_ap_int, ap_img) == false)
-                        {
-                            continue;
-                        }
-
-                        switch (beam->get_flavor()) {
-                        case 'a':
-                            dose = 0;
-                            rgdepth = beam->rpl_vol->get_rgdepth (ct_xyz);
-                            WER =  compute_PrWER_from_HU(beam->rpl_ct_vol_HU->get_rgdepth(ct_xyz));
-
-                            for (size_t beam_idx = 0; beam_idx < beam->get_mebs()->get_depth_dose().size(); beam_idx++)
-                            {
-                                particle_number = beam->get_mebs()->get_particle_number_xyz(idx_ap_int, rest, beam_idx, beam->get_aperture()->get_dim());
-                                if (particle_number != 0 && rgdepth >=0 && rgdepth < beam->get_mebs()->get_depth_dose()[beam_idx]->dend) 
-                                {
-                                    dose += particle_number * WER * energy_direct (rgdepth, beam, beam_idx);
-                                }
-                            }
-                            break;
-                        }
-
-                        /* Insert the dose into the dose volume */
-                        idx = volume_index (dose_vol->dim, ct_ijk);
-                        dose_img[idx] = dose;
-                    }
-                }
-            }
-            display_progress ((float)idx, (float)ct_vol->npix);
+        // Add range compensator to rpl volume
+        if (beam->rsp_accum_vol->get_aperture()->have_range_compensator_image())
+        {
+            add_rcomp_length_to_rpl_volume(beam);
         }
+        
+        // Loop through energies
+        compute_dose_ray_trace_dij_b (beam, ct_vol, dose_vol);
+        d_ptr->rt_dose_timing->timer_dose_calc.stop ();
 
-	/* Dose normalization process*/
-	if (this->get_non_norm_dose() != 'y')
-	{
-            if (this->get_have_ref_dose_point()) // case 1: ref dose point defined
-            {
-                float rdp_ijk[3] = {0,0,0};
-                float rdp[3] = {this->get_ref_dose_point(0), this->get_ref_dose_point(1), this->get_ref_dose_point(2)};
-                rdp_ijk[0] = (rdp[0] - dose_vol->origin[0]) / dose_vol->spacing[0];
-                rdp_ijk[1] = (rdp[1] - dose_vol->origin[1]) / dose_vol->spacing[1];
-                rdp_ijk[2] = (rdp[2] - dose_vol->origin[2]) / dose_vol->spacing[2];
-			
-                if (rdp_ijk[0] >=0 && rdp_ijk[1] >=0 && rdp_ijk[2] >=0 && rdp_ijk[0] < dose_vol->dim[0] && rdp_ijk[1] < dose_vol->dim[1] && rdp_ijk[2] < dose_vol->dim[2])
-                {
-                    printf("Dose normalized to the dose reference point.\n");
-                    dose_normalization_to_dose_and_point(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), rdp_ijk, rdp, beam); // if no normalization dose, norm_dose = 1 by default
-                    if (this->get_have_dose_norm())
-                    {
-                        printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose());
-                    }
-                    else
-                    {
-                        printf("%lg x 100%%.\n", beam->get_beam_weight());
-                    }
-                    printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1));
-                }
-                else
-                {
-                    printf("***WARNING***\nThe reference dose point is not in the image volume.\n");
-                    dose_normalization_to_dose(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), beam);
-                    if (this->get_have_dose_norm())
-                    {
-                        printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose());
-                    }
-                    else
-                    {
-                        printf("%lg x 100%%.\n", beam->get_beam_weight());
-                    }
-                    printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1));
-                }
-            }
-            else // case 2: no red dose point defined
-            {				
-                dose_normalization_to_dose(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), beam); // normalization_dose = 1 if no dose_prescription is set
-                if (this->get_have_dose_norm())
-                {
-                    printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose());
-                }
-                else
-                {
-                    printf("%lg x 100%%.\n", beam->get_beam_weight());
-                }
-                printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1));
-            }
-	}
-	else // raw dose, dose not normalized
-	{
-            for (int i = 0; i < dose_vol->dim[0] * dose_vol->dim[1] * dose_vol->dim[2]; i++)
-            {
-                dose_img[i] *= beam->get_beam_weight();
-            }
-	}
-
-        Plm_image::Pointer dose = Plm_image::New();
-        dose->set_volume (dose_vol);
-        beam->set_dose(dose);
+        d_ptr->rt_dose_timing->timer_reformat.resume ();
+        dose_volume_reconstruction (beam->dose_rv, dose_vol);
+        d_ptr->rt_dose_timing->timer_reformat.stop ();
+    }
+    else if (beam->get_flavor() == "d") {
 
-        printf ("Sigma conversion: %f seconds\n", time_sigma_conv);
-        printf ("Dose calculation: %f seconds\n", time_dose_calc);
-        printf ("Dose reformat: %f seconds\n", time_dose_reformat);
-        printf ("Dose overhead: %f seconds\n", time_dose_misc); fflush(stdout);
+        // Loop through energies
+        Rt_mebs::Pointer mebs = beam->get_mebs();
+        std::vector<Rt_depth_dose*> depth_dose = mebs->get_depth_dose();
+        for (size_t i = 0; i < depth_dose.size(); i++) {
+            compute_dose_d (beam, i, ct_vol);
+        }
+        d_ptr->rt_dose_timing->timer_reformat.resume ();
+        dose_volume_reconstruction (beam->dose_rv, dose_vol);
+        d_ptr->rt_dose_timing->timer_reformat.stop ();
     }
 
+    d_ptr->rt_dose_timing->timer_misc.resume ();
+    Plm_image::Pointer dose = Plm_image::New();
+    dose->set_volume (dose_vol);
+    beam->set_dose (dose);
+    this->normalize_beam_dose (beam);
+    d_ptr->rt_dose_timing->timer_misc.stop ();
+}
+
 Plm_return_code
 Rt_plan::compute_plan ()
 {
+    d_ptr->rt_dose_timing->reset ();
+    
     if (!d_ptr->rt_parms) {
         print_and_exit ("Error: cannot compute_plan without an Rt_parms\n");
     }
@@ -774,155 +581,68 @@ Rt_plan::compute_plan ()
             "not specified in configuration file!\n");
     }
 
-    /* Load the patient CT image and save into the plan */
+    /* Load the patient CT image */
+    d_ptr->rt_dose_timing->timer_io.resume ();
     Plm_image::Pointer ct = Plm_image::New (d_ptr->patient_fn,
         PLM_IMG_TYPE_ITK_FLOAT);
     if (!ct) {
         print_and_exit ("Error: Unable to load patient volume.\n");
     }
     this->set_patient (ct);
-    this->print_verif ();
 
+    /* Load the patient target structure */
+    this->load_target ();
+    d_ptr->rt_dose_timing->timer_io.stop ();
+
+    /* Display debugging information */
+    d_ptr->rt_dose_timing->timer_misc.resume ();
+    this->print_verif ();
+    
     Volume::Pointer ct_vol = this->get_patient_volume ();
     Volume::Pointer dose_vol = ct_vol->clone_empty ();
     plm_long dim[3] = {dose_vol->dim[0], dose_vol->dim[1], dose_vol->dim[2]};
     float* total_dose_img = (float*) dose_vol->img;
-
+    d_ptr->rt_dose_timing->timer_misc.stop ();
+    
     for (size_t i = 0; i < d_ptr->beam_storage.size(); i++)
     {
         printf ("\nStart dose calculation Beam %d\n", (int) i + 1);
         Rt_beam *beam = d_ptr->beam_storage[i];
 
-        /* try to generate plan with the provided parameters */
-        if (!this->prepare_beam_for_calc (beam)) {
-            print_and_exit ("ERROR: Unable to initilize plan.\n");
-        }
-        /* Compute beam modifiers, SOBP etc. according to the teatment strategy */
-        beam->compute_prerequisites_beam_tools(this->get_target());
-
-        /* GCS FIX: The below code is commented out by Max.  
-           Need to figure out if it can be safely deleted. */
-#if defined (commentout)
-        if (beam->get_beam_line_type() == "passive")
-        {
-            /* handle auto-generated beam modifiers */
-            if (d_ptr->target_fn != "") {
-                printf ("Target fn = %s\n", d_ptr->target_fn.c_str());
-                this->set_target (d_ptr->target_fn);
-                beam->compute_beam_modifiers(this->get_target()->get_vol());
-            }
-	
-            /* generate depth dose curve, might be manual peaks or 
-               optimized based on prescription, or automatic based on target */
-
-            if ((beam->get_mebs()->get_have_copied_peaks() == false && beam->get_mebs()->get_have_prescription() == false && d_ptr->target_fn == "")||(beam->get_mebs()->get_have_manual_peaks() == true)) {
-		
-                /* Manually specified, so do not optimize */
-                if (!beam->get_mebs()->generate ()) {
-                    return PLM_ERROR;
-                }
-            } 
-            else if (d_ptr->target_fn != "" && !beam->get_mebs()->get_have_prescription()) {
-                /* Optimize based on target volume */
-                Rpl_volume *rpl_vol = beam->rpl_vol;
-                beam->get_mebs()->set_prescription(rpl_vol->get_min_wed() - beam->get_mebs()->get_proximal_margin(), rpl_vol->get_max_wed() + beam->get_mebs()->get_distal_margin());
-                beam->get_mebs()->optimize_sobp ();
-            } else {
-                /* Optimize based on manually specified range and modulation */
-                beam->get_mebs()->optimize_sobp ();
-            }
-			
-            /* compute the pencil beam spot matrix for passive beams */
-            beam->get_mebs()->initialize_and_compute_particle_number_matrix_passive(beam->get_aperture());
-        }
-        else // active
-        {
-            // to be computed
-
-            /* Compute the aperture and wed matrices */
-            if (beam->get_mebs()->get_have_particle_number_map() == false)
-            {
-                /* we extract the max and min energies to cover the target/prescription */
-                beam->compute_beam_modifiers(
-                    beam->get_mebs()->compute_particle_number_matrix_from_target_active(beam->rpl_vol, beam->get_target(), beam->get_aperture());
-                    }
-                else // spot map exists as a txt file
-                {
-                    beam->get_mebs()->initialize_and_read_particle_number_matrix_active(beam->get_aperture());
-                }
-            }
-        }
-#endif
-            
         /* Generate dose */
         this->set_debug (true);
         this->compute_dose (beam);
 
-        /* Save beam modifiers */
-        if (beam->get_aperture_out() != "") {
-            Rpl_volume *rpl_vol = beam->rpl_vol;
-            Plm_image::Pointer& ap = rpl_vol->get_aperture()->get_aperture_image();
-            ap->save_image (beam->get_aperture_out().c_str());
-        }
-
-        if (beam->get_range_compensator_out() != "" && beam->get_beam_line_type() == "passive") {
-            Rpl_volume *rpl_vol = beam->rpl_vol;
-            Plm_image::Pointer& rc = rpl_vol->get_aperture()->get_range_compensator_image();
-            rc->save_image (beam->get_range_compensator_out().c_str());
-        }
-
-        /* Save projected density volume */
-        if (d_ptr->output_proj_img_fn != "") {
-            Rpl_volume* proj_img = beam->rpl_ct_vol_HU;
-            if (proj_img) {
-                proj_img->save (beam->get_proj_img_out());
-            }
-        }
-
-        /* Save projected dose volume */
-        if (beam->get_proj_dose_out() != "") {
-            Rpl_volume* proj_dose = beam->rpl_dose_vol;
-            if (proj_dose) {
-                proj_dose->save (beam->get_proj_dose_out());
-            }
-        }
-
-        /* Save sigma volume */
-        if (beam->get_sigma_out() != "") {
-            Rpl_volume* sigma_img = beam->sigma_vol;
-            if (sigma_img) {
-                sigma_img->save (beam->get_sigma_out());
-            }
-        }
-
-        /* Save wed volume */
-        if (beam->get_wed_out() != "") {
-            Rpl_volume* rpl_vol = beam->rpl_vol;
-            if (rpl_vol) {
-                rpl_vol->save (beam->get_wed_out());
-            }
-        }
-
-        /* Save the spot map */
-        if (beam->get_mebs()->get_particle_number_out() != "") {
-            beam->get_mebs()->export_spot_map_as_txt(beam->get_aperture());
-        }
-
-        float* beam_dose_img = (float*) d_ptr->beam_storage[i]->get_dose()->get_volume()->img;
+        /* Save beam data */
+        d_ptr->rt_dose_timing->timer_io.resume ();
+        beam->save_beam_output ();
+        d_ptr->rt_dose_timing->timer_io.stop ();
 
         /* Dose cumulation to the plan dose volume */
+        d_ptr->rt_dose_timing->timer_misc.resume ();
+        float* beam_dose_img = (float*) d_ptr->beam_storage[i]->get_dose()->get_volume()->img;
         for (int j = 0; j < dim[0] * dim[1] * dim[2]; j++)
         {
             total_dose_img[j] += beam_dose_img[j];
         }
+        d_ptr->rt_dose_timing->timer_misc.stop ();
     }
 
+    /* Save stopping power image */
+    d_ptr->rt_dose_timing->timer_io.resume ();
+    if (d_ptr->output_psp_fn != "") {
+        d_ptr->patient_psp->save_image (d_ptr->output_psp_fn);
+    }
+    
     /* Save dose output */
     Plm_image::Pointer dose = Plm_image::New();
     dose->set_volume (dose_vol);
     this->set_dose(dose);
     this->get_dose()->save_image (d_ptr->output_dose_fn.c_str());
+    d_ptr->rt_dose_timing->timer_io.stop ();
 
+    d_ptr->rt_dose_timing->report ();
+    
     printf ("done.  \n\n");
     return PLM_SUCCESS;
 }
@@ -940,28 +660,21 @@ Rt_plan::get_dose_itk ()
 }
 
 void 
-Rt_plan::set_output_dose (const std::string& output_dose_fn)
+Rt_plan::set_output_dose_fn (const std::string& output_dose_fn)
 {
     d_ptr->output_dose_fn = output_dose_fn;
 }
 
 void 
-Rt_plan::set_dose(Plm_image::Pointer& dose)
+Rt_plan::set_output_psp_fn (const std::string& output_psp_fn)
 {
-    d_ptr->dose = dose;
+    d_ptr->output_psp_fn = output_psp_fn;
 }
 
-static inline void
-display_progress (
-    float is,
-    float of
-) 
+void 
+Rt_plan::set_dose (Plm_image::Pointer& dose)
 {
-#if defined (PROGRESS)
-    printf (" [%3i%%]\b\b\b\b\b\b\b",
-        (int)floorf((is/of)*100.0f));
-    fflush (stdout);
-#endif
+    d_ptr->dose = dose;
 }
 
 void
@@ -976,7 +689,7 @@ Rt_plan::print_verif ()
 
     printf("\n \n [SETTINGS]");
     int num_beams = d_ptr->beam_storage.size();
-    printf("\n flavor: "); for (int i = 0; i < num_beams; i++) {printf("%c ** ", d_ptr->beam_storage[i]->get_flavor());}
+    printf("\n flavor: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_flavor().c_str());}
     printf("\n homo_approx: "); for (int i = 0; i < num_beams; i++) {printf("%c ** ", d_ptr->beam_storage[i]->get_homo_approx());}
     printf("\n ray_step: "); for (int i = 0; i < num_beams; i++) {printf("%lg ** ", d_ptr->beam_storage[i]->get_step_length());}
     printf("\n aperture_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_aperture_out().c_str());}
@@ -1024,4 +737,5 @@ Rt_plan::print_verif ()
             printf("%lg ** ", d_ptr->beam_storage[i]->get_mebs()->get_weight()[j]);
         }
     }
+    printf ("\n");
 }
diff --git a/src/plastimatch/dose/rt_plan.h b/src/plastimatch/dose/rt_plan.h
index 3889d98..1e5be5a 100644
--- a/src/plastimatch/dose/rt_plan.h
+++ b/src/plastimatch/dose/rt_plan.h
@@ -28,6 +28,7 @@ public:
 
 public:
     Plm_return_code parse_args (int argc, char* argv[]);
+    Plm_return_code set_command_file (const char *command_file);
 
     /* Set the CT volume for dose calculation.
        The Rt_plan takes ownership of this CT/Patient. */
@@ -46,6 +47,7 @@ public:
     void set_target (UCharImageType::Pointer&);
     void set_target (FloatImageType::Pointer&);
     Plm_image::Pointer& get_target ();
+    void load_target ();
 
     /* Set/Get Rt_study */
     void set_rt_study(Rt_study* rt_study);
@@ -72,34 +74,36 @@ public:
     /* Get the position of the beam isocenter in world coordinates. */
     const float* get_ref_dose_point () const;
     /* Get the x, y, or z coordinate of the beam source 
-      in world coordinates. */
+       in world coordinates. */
     float get_ref_dose_point (int dim) const;
     /* Set the position of the beam isocenter in world coordinates. */
     void set_ref_dose_point (const float rdp[3]);
     /* Set the position of the beam isocenter in world coordinates. */
     void set_ref_dose_point (const double rdp[3]);
 
-	/* Set / Get the declaration of the normalization conditions*/
-	void set_have_ref_dose_point(bool have_rdp);
-	bool get_have_ref_dose_point();
-	void set_have_dose_norm(bool have_dose_norm);
-	bool get_have_dose_norm();
+    /* Set / Get the declaration of the normalization conditions*/
+    void set_have_ref_dose_point(bool have_rdp);
+    bool get_have_ref_dose_point();
+    void set_have_dose_norm(bool have_dose_norm);
+    bool get_have_dose_norm();
 
-	/*! \brief Get the "non normalized" dose option */
+    /*! \brief Get the "non normalized" dose option */
     char get_non_norm_dose () const;
     /*! \brief Set "non normalized" dose option */
     void set_non_norm_dose (char non_norm_dose);
 
     /* Compute dose */
+    void create_patient_psp ();
     void propagate_target_to_beams ();
-    bool prepare_beam_for_calc (Rt_beam *beam);
     void compute_dose (Rt_beam *beam);
     Plm_return_code compute_plan ();
+    void normalize_beam_dose (Rt_beam *beam);
 
-    /* Get outputs */
+    /* Getting outputs and creating output files */
     Plm_image::Pointer get_dose ();
     FloatImageType::Pointer get_dose_itk ();
-    void set_output_dose (const std::string& output_dose_fn);
+    void set_output_dose_fn (const std::string& output_dose_fn);
+    void set_output_psp_fn (const std::string& output_psp_fn);
     void set_dose(Plm_image::Pointer& dose);
 
     void print_verif ();
diff --git a/src/plastimatch/dose/rt_sigma.cxx b/src/plastimatch/dose/rt_sigma.cxx
old mode 100644
new mode 100755
index d0afbe4..1ad6d95
--- a/src/plastimatch/dose/rt_sigma.cxx
+++ b/src/plastimatch/dose/rt_sigma.cxx
@@ -1,6 +1,7 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
+#include "plmdose_config.h"
 
 #include "ray_data.h"
 #include "rpl_volume.h"
@@ -8,17 +9,19 @@
 #include "rt_lut.h"
 #include "rt_sigma.h"
 
-void compute_sigmas (
-    Rt_plan* plan,
+void
+compute_sigmas (
     const Rt_beam* beam,
     float energy,
     float* sigma_max, 
-	std::string size, 
-	int* margins)
+    std::string size, 
+    int* margins)
 {
-    /* We compute the sigmas for source, range compensator and patient as described in the Hong's paper */
-    /* First we set the volume in which the sigmas have to be calculated: the normal rpl_sigma_volume,  */
-    /* or the extended rpl_sigma_volume for margins. */
+    // We compute the sigmas for source, range compensator and patient
+    // as described in the Hong's paper.
+    // First we set the volume in which the sigmas have to be calculated:
+    // the normal rpl_sigma_volume, or the extended rpl_sigma_volume
+    // for margins.
 
     Rpl_volume* sigma_vol;
     Rpl_volume* ct_vol;
@@ -27,23 +30,23 @@ void compute_sigmas (
     if (size == "small")
     {
         sigma_vol = beam->sigma_vol;
-        ct_vol = beam->rpl_ct_vol_HU;
-        rgl_vol = beam->rpl_vol;
+        ct_vol = beam->hu_samp_vol;
+        rgl_vol = beam->rsp_accum_vol;
     }
     else
     {
         sigma_vol = beam->sigma_vol_lg;
-        ct_vol = beam->rpl_ct_vol_HU_lg;
+        ct_vol = beam->rpl_vol_samp_lg;
         rgl_vol = beam->rpl_vol_lg;
     }
 
     /* Now that the volumes were defined, we can compute the sigmas in them and do the quadratic sigmas sum */
     /* sigma^2 patient */
-    compute_sigma_pt (sigma_vol, rgl_vol, ct_vol, plan, beam, energy);
+    compute_sigma_pt (sigma_vol, rgl_vol, ct_vol, beam, energy);
     /* + sigma^2 source */
     if (beam->get_source_size() > 0)
     {            
-        compute_sigma_source(sigma_vol, rgl_vol, plan, beam, energy);
+        compute_sigma_source (sigma_vol, rgl_vol, beam, energy);
     }
     else
     {
@@ -52,7 +55,7 @@ void compute_sigmas (
     /* + sigma^2 range compensator */
     if (beam->get_aperture()->have_range_compensator_image() && energy > 1)
     {            
-        compute_sigma_range_compensator(sigma_vol, rgl_vol, plan, beam, energy, margins);
+        compute_sigma_range_compensator(sigma_vol, rgl_vol, beam, energy, margins);
     }
     else
     {
@@ -83,7 +86,6 @@ void compute_sigma_pt (
     Rpl_volume* sigma_vol,
     Rpl_volume* rpl_volume,
     Rpl_volume* ct_vol,
-    Rt_plan* plan,
     const Rt_beam* beam,
     float energy)
 {
@@ -91,17 +93,18 @@ void compute_sigma_pt (
 
     if (beam->get_homo_approx() == 'y')
     {
-        sigma_max = compute_sigma_pt_homo(sigma_vol, rpl_volume, energy);
+        sigma_max = compute_sigma_pt_homo (sigma_vol, rpl_volume, energy);
     }
     else
     {
-        sigma_max = compute_sigma_pt_hetero(sigma_vol, rpl_volume, ct_vol, energy);
+        sigma_max = compute_sigma_pt_hetero (sigma_vol, rpl_volume, ct_vol, energy);
     }
     printf("Sigma patient computed - sigma_pt_max = %lg mm.\n", sigma_max);
     return;
 }
 
-float compute_sigma_pt_homo (
+float
+compute_sigma_pt_homo (
     Rpl_volume* sigma_vol,
     Rpl_volume* rpl_vol,
     float energy)
@@ -116,60 +119,61 @@ float compute_sigma_pt_homo (
         printf("Error: rpl_vol & sigma_vol have different dimensions. Sigma volume not built\n");
         return 0;
     }
-    /* At this time, sigma_vol contains the range length, WITHOUT range compensator */
+    // At this time, sigma_vol contains the range length,
+    // WITHOUT range compensator
     float* sigma_volume = (float*) sigma_vol->get_vol()->img;
     float* rpl_img = (float*) rpl_vol->get_vol()->img;
-    unsigned char* ap_img = NULL;
 
     double x_over_range = 0;
 	
-    if (rpl_vol->get_aperture()->have_aperture_image())
-    {
+    unsigned char* ap_img = 0;
+    if (rpl_vol->get_aperture()->have_aperture_image()) {
         ap_img = (unsigned char*) rpl_vol->get_aperture()->get_aperture_volume()->img;
     } 
-    /*  Hong method to calculate the sigma value for homogeneous medium */
-    /* Range value in water extracted from a fit based on 1-250MeV from the NIST data - ranges in mm */
+    /* Hong method to calculate the sigma value for homogeneous medium */
+    /* Range value in water extracted from a fit based on 1-250MeV 
+       from the NIST data - ranges in mm */
     double range = 10 * get_proton_range(energy);
     
-    /* Sigma0 value from the Hong fit - See paper Hong "A pencil beam algorithm for proton dose calculation" - sigma in mm: x10 */
+    // Sigma0 value from the Hong fit - See paper Hong "A pencil beam 
+    // algorithm for proton dose calculation" - sigma in mm: x10
     double sigma0 = 0.02275 * range + 1.2085E-6 * range * range;
 
     /* Calculation of the sigma values from the medium equivalent depth  */
-    for (int i = 0; i < dim[0] * dim [1]; i++)
-    {
-        for (int k = 0; k < dim[2]; k++)
-        {
-            idx = k * dim[0] * dim[1] +i;
-            if (!rpl_vol->get_aperture()->have_aperture_image() || (rpl_vol->get_aperture()->have_aperture_image() && ap_img[i] > 0))
+    for (int i = 0; i < dim[0] * dim [1]; i++) {
+        for (int k = 0; k < dim[2]; k++) {
+            idx = k * dim[0] * dim[1] + i;
+            if (ap_img && ap_img[i] == 0) {
+                continue;
+            }
+            if (rpl_img[idx] <= 0) 
             {
-                if (rpl_img[idx] <= 0) 
-                {
-                    sigma_volume[idx] = 0;
-                }
-                else if (rpl_img[idx] >= range)
-                {
-                    sigma_volume[idx] = sigma0 * sigma0; // sigma will contains the square of the sigmas to do the quadratic sum
+                sigma_volume[idx] = 0;
+            }
+            else if (rpl_img[idx] >= range)
+            {
+                // sigma will contains the square of the sigmas to do
+                // the quadratic sum
+                sigma_volume[idx] = sigma0 * sigma0; 
             
-                    /* sigma_max update */
-                    if (sigma0 > sigma_max)
-                    {
-                        sigma_max = sigma0;
-                    }
-                }
-                else
+                /* sigma_max update */
+                if (sigma0 > sigma_max)
                 {
-                    x_over_range = rpl_img[idx] / range;
+                    sigma_max = sigma0;
+                }
+            }
+            else
+            {
+                x_over_range = rpl_img[idx] / range;
 
-                    /* sigma = y0 * Hong (x/range) */
-                    sigma_volume[idx] = sigma0 * x_over_range * ( 0.26232 + 0.64298 * x_over_range + 0.0952393 * x_over_range * x_over_range);
-            
-                    /* sigma_max update */
-                    if (sigma_volume[idx] > sigma_max)
-                    {
-                        sigma_max = sigma_volume[idx];
-                    }
-                    sigma_volume[idx] *= sigma_volume[idx]; // We return sigma^2 to sigma_vol
+                /* sigma = y0 * Hong (x/range) */
+                sigma_volume[idx] = sigma0 * x_over_range * ( 0.26232 + 0.64298 * x_over_range + 0.0952393 * x_over_range * x_over_range);
+
+                if (sigma_volume[idx] > sigma_max) {
+                    sigma_max = sigma_volume[idx];
                 }
+                // We return sigma^2 to sigma_vol
+                sigma_volume[idx] *= sigma_volume[idx];
             }
         }
     }
@@ -178,19 +182,19 @@ float compute_sigma_pt_homo (
 
 float compute_sigma_pt_hetero (
     Rpl_volume* sigma_vol,
-    Rpl_volume* rgl_vol,
+    Rpl_volume* rpl_vol,
     Rpl_volume* ct_vol,
     float energy)
 {
     float sigma_max = 0;
 
     float* sigma_img = (float*) sigma_vol->get_vol()->img;
-    float* rpl_img = (float*) rgl_vol->get_vol()->img;
+    float* rpl_img = (float*) rpl_vol->get_vol()->img;
     float* ct_img = (float*) ct_vol->get_vol()->img;
     unsigned char* ap_img = 0;
-    if (rgl_vol->get_aperture()->have_aperture_image())
+    if (rpl_vol->get_aperture()->have_aperture_image())
     {
-        ap_img = (unsigned char*) rgl_vol->get_aperture()->get_aperture_volume()->img;
+        ap_img = (unsigned char*) rpl_vol->get_aperture()->get_aperture_volume()->img;
     }
     plm_long dim[3] = { sigma_vol->get_vol()->dim[0], sigma_vol->get_vol()->dim[1], sigma_vol->get_vol()->dim[2]};
 
@@ -203,7 +207,7 @@ float compute_sigma_pt_hetero (
     float spacing = sigma_vol->get_vol()->spacing[2]/10; // in cm to correspond to the Highland formula
 
     float E = energy;
-	float mc2 = (float) PROTON_REST_MASS;		/* proton mass at rest (MeV) */
+    float mc2 = (float) PROTON_REST_MASS;		/* proton mass at rest (MeV) */
     float c = (float) LIGHT_SPEED;						/* speed of light (m/s) */
     float p = 0.0;								/* Proton momentum (passed in) */
     float v = 0.0;								/* Proton velocity (passed in) */
@@ -219,10 +223,10 @@ float compute_sigma_pt_hetero (
     printf ("sigma_img: %d %d %d\n", (int) sigma_vol->get_vol()->dim[0], 
         (int) sigma_vol->get_vol()->dim[1], (int) sigma_vol->get_vol()->dim[2]);
     printf("dim: %d %d %d\n", (int) dim[0], (int) dim[1], (int) dim[2]);
-	
+
     for (int apert_idx = 0; apert_idx < dim[0] * dim[1]; apert_idx++)
     {   
-        if (!rgl_vol->get_aperture()->have_aperture_image() || (rgl_vol->get_aperture()->have_aperture_image() && ap_img[apert_idx] > 0))
+        if (!rpl_vol->get_aperture()->have_aperture_image() || (rpl_vol->get_aperture()->have_aperture_image() && ap_img[apert_idx] > 0))
         {
             int first_non_null_loc = 0;
             for (int s = 0; s < dim[2]; s++)
@@ -250,13 +254,16 @@ float compute_sigma_pt_hetero (
                 }
             }
     
-            /* Step 2: Each pixel in the volume will receive its sigma (in reality y0) value, according to the differential Highland formula */
-  
+            // Step 2: Each pixel in the volume will receive its sigma 
+            // (in reality y0) value, according to the differential
+            // Highland formula */
             std::vector<double> pv_cache (dim[2], 0);
             std::vector<double> inv_rad_len (dim[2], 0);
             std::vector<double> stop_cache (dim[2], 0);
 
-            E = energy; // we set the energy of the particles to the nominal energy for this ray
+            // we set the energy of the particles to the nominal energy
+            // for this ray
+            E = energy;
 
             for (int s = first_non_null_loc; s < dim[2]; s++)
             {
@@ -264,9 +271,11 @@ float compute_sigma_pt_hetero (
                 v = c*sqrt(1-pow((mc2/(E+mc2)),2)); //in m.s-1
                 pv_cache[s] = p * v;
 
+                /* GCS FIX: The X0 depends on radiation length, not 
+                   proton stopping power.  Yuck.  */
+                // dE/dx_mat = dE /dx_watter * STPR (lut in g/cm2)
                 inv_rad_len[s] = 1.0f / compute_X0_from_HU(HU_ray[s]);
-                stop_cache[s] = compute_PrSTPR_from_HU(HU_ray[s]) * get_proton_stop(E); // dE/dx_mat = dE /dx_watter * STPR (lut in g/cm2)
-
+                stop_cache[s] = compute_PrSTPR_from_HU(HU_ray[s]) * get_proton_stop(E);
                 sum = 0;
                 inverse_rad_length_integrated = 0;
 
@@ -328,7 +337,10 @@ float compute_sigma_pt_hetero (
     return sigma_max;
 }
 
-void compute_sigma_source (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_plan* plan, const Rt_beam *beam, float energy)
+void
+compute_sigma_source (
+    Rpl_volume* sigma_vol, Rpl_volume* rpl_volume,
+    const Rt_beam *beam, float energy)
 {
     /* Method of the Hong's algorithm - See Hong's paper */
     float* sigma_img = (float*) sigma_vol->get_vol()->img;
@@ -343,8 +355,8 @@ void compute_sigma_source (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_pla
 
     /* MD Fix: Why plan->ap->nrm is incorrect at this point??? */
     double nrm[3] = {0,0,0};
-    vec3_sub3(nrm, beam->get_source_position(), beam->get_isocenter_position());
-    vec3_normalize1(nrm);
+    vec3_sub3 (nrm, beam->get_source_position(), beam->get_isocenter_position());
+    vec3_normalize1 (nrm);
 
     plm_long dim[3] = { sigma_vol->get_vol()->dim[0], sigma_vol->get_vol()->dim[1], sigma_vol->get_vol()->dim[2]};
     float range = get_proton_range(energy);
@@ -353,7 +365,7 @@ void compute_sigma_source (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_pla
     {
         if (ap_img[i] > 0)
         {
-            Ray_data* ray_data = &sigma_vol->get_Ray_data()[i];
+            Ray_data* ray_data = &sigma_vol->get_ray_data()[i];
             proj = -vec3_dot(ray_data->ray, nrm);
             dist_cp = vec3_dist(ray_data->cp,beam->get_source_position());
 
@@ -377,15 +389,17 @@ void compute_sigma_source (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_pla
             }
         }
     }
-    printf("Sigma source computed - sigma_source_max = %lg mm.\n", sigma_max);
-	return;
+    printf ("Sigma source computed - sigma_source_max = %lg mm.\n", sigma_max);
 }
 
-void compute_sigma_range_compensator(Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_plan* plan, const Rt_beam *beam, float energy, int* margins)
+void
+compute_sigma_range_compensator (
+    Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, 
+    const Rt_beam *beam, float energy, int* margins)
 {
-	/* There are two methods for computing the beam spread due to a range compensator */
+    /* There are two methods for computing the beam spread due to a range compensator */
     /* Method1 rc_MC_model:  Hong's algorithm (Highland)- See Hong's paper */
-	/* Method2:  model built on Monte Carlo simulations - Paper still unpublished */
+    /* Method2:  model built on Monte Carlo simulations - Paper still unpublished */
     /* The range compensator is supposed to be made of lucite and placed right after the aperture*/
 	
     if (energy < 1)
@@ -396,17 +410,17 @@ void compute_sigma_range_compensator(Rpl_volume* sigma_vol, Rpl_volume* rpl_volu
     /* Range value in lucite extracted from a fit based on 1-250MeV from the NIST data - ranges in mm */
     double range = 10 * get_proton_range((double) energy);
 
-	/* Theta0 computation */
-	double theta0 = 0;
+    /* Theta0 computation */
+    double theta0 = 0;
 
-	if (beam->get_rc_MC_model() != 'y')
-	{
-			theta0 = get_theta0_Highland(range);
-	}
-	else
-	{
-			theta0 = get_theta0_MC(energy);
-	}
+    if (beam->get_rc_MC_model() != 'y')
+    {
+        theta0 = get_theta0_Highland(range);
+    }
+    else
+    {
+        theta0 = get_theta0_MC(energy);
+    }
 
     /* sigma calculation and length computations */
     float* sigma_img = (float*) sigma_vol->get_vol()->img;
@@ -440,41 +454,39 @@ void compute_sigma_range_compensator(Rpl_volume* sigma_vol, Rpl_volume* rpl_volu
     double sigma;
     double nrm[3] = {0,0,0};
 		
-	/* MD Fix: Why plan->ap->nrm is incorrect at this point??? */
-    vec3_sub3(nrm, beam->get_source_position(), beam->get_isocenter_position());
+    /* MD Fix: Why plan->ap->nrm is incorrect at this point??? */
+    vec3_sub3 (nrm, beam->get_source_position(), beam->get_isocenter_position());
     vec3_normalize1(nrm);
 	
-    if (margins[0] == 0 && margins[1] == 0 || beam->get_flavor() != 'h')
-    {
-        for (int i = 0; i < dim[0] * dim[1]; i++)
-        {
+    if (margins[0] == 0 && margins[1] == 0) {
+        for (int i = 0; i < dim[0] * dim[1]; i++) {
             /* calculation of sigma_srm, see graph A3 from the Hong's paper */
-			if (!rpl_volume->get_aperture()->have_aperture_image() || (ap_img && ap_img[i] > 0))
+            if (!rpl_volume->get_aperture()->have_aperture_image() || (ap_img && ap_img[i] > 0))
             {
-                Ray_data* ray_data = &sigma_vol->get_Ray_data()[i];
+                Ray_data* ray_data = &sigma_vol->get_ray_data()[i];
 	        
                 proj = -vec3_dot(ray_data->ray, nrm);
-				if (proj == 0) 
-				{ 
-					printf("error: some rays are perpendicular to the beam axis \n");
-					return;
-				}
+                if (proj == 0) 
+                { 
+                    printf("error: some rays are perpendicular to the beam axis \n");
+                    return;
+                }
 
                 dist_cp = vec3_dist(ray_data->cp, beam->get_source_position());
                 rc_over_range =  rc_img[i] / proj * PMMA_DENSITY * PMMA_STPR / range; // energy is >1, so range > 0 (range is in water: rho * WER)
 	
                 if (rc_over_range < 1)
                 {
-					if (beam->get_rc_MC_model() != 'y')
-					{
-						theta_srm =  theta0 * get_theta_rel_Highland(rc_over_range);
-						rc_eff = get_scat_or_Highland(rc_over_range) * rc_img[i];
-					}
-					else
-					{
-						theta_srm =  theta0 * get_theta_rel_MC(rc_over_range);
-						rc_eff = get_scat_or_MC(rc_over_range) * rc_img[i];
-					}
+                    if (beam->get_rc_MC_model() != 'y')
+                    {
+                        theta_srm =  theta0 * get_theta_rel_Highland(rc_over_range);
+                        rc_eff = get_scat_or_Highland(rc_over_range) * rc_img[i];
+                    }
+                    else
+                    {
+                        theta_srm =  theta0 * get_theta_rel_MC(rc_over_range);
+                        rc_eff = get_scat_or_MC(rc_over_range) * rc_img[i];
+                    }
 	
                     for (int j = 0; j < dim[2]; j++)
                     {
@@ -526,31 +538,31 @@ void compute_sigma_range_compensator(Rpl_volume* sigma_vol, Rpl_volume* rpl_volu
                 /* calculation of sigma_srm, see graph A3 from the Hong's paper */
                 if (!rpl_volume->get_aperture()->have_aperture_image() || (rpl_volume->get_aperture()->have_aperture_image() && ap_img[idx2d_sm] > 0))
                 {
-					Ray_data* ray_data = &sigma_vol->get_Ray_data()[idx2d_lg];
+                    Ray_data* ray_data = &sigma_vol->get_ray_data()[idx2d_lg];
 	        
-					proj = -vec3_dot(ray_data->ray, nrm);
+                    proj = -vec3_dot(ray_data->ray, nrm);
 
-					if (proj == 0) 
-					{ 
-						printf("error: some rays are perpendicular to the beam axis \n");
-						return;
-					}
+                    if (proj == 0) 
+                    { 
+                        printf("error: some rays are perpendicular to the beam axis \n");
+                        return;
+                    }
 
-					dist_cp = vec3_dist(ray_data->cp, beam->get_source_position());
+                    dist_cp = vec3_dist(ray_data->cp, beam->get_source_position());
                     rc_over_range = rc_img[idx2d_sm] / proj * PMMA_DENSITY * PMMA_STPR / range; // energy is >1, so range > 0
 
                     if (rc_over_range < 1)
                     {
-						if (beam->get_rc_MC_model() != 'y')
-						{
-							theta_srm =  theta0 * get_theta_rel_Highland(rc_over_range);
-							rc_eff = get_scat_or_Highland(rc_over_range) * rc_img[idx2d_sm];
-						}
-						else
-						{
-							theta_srm =  theta0 * get_theta_rel_MC(rc_over_range);
-							rc_eff = get_scat_or_MC(rc_over_range) * rc_img[idx2d_sm];
-						}
+                        if (beam->get_rc_MC_model() != 'y')
+                        {
+                            theta_srm =  theta0 * get_theta_rel_Highland(rc_over_range);
+                            rc_eff = get_scat_or_Highland(rc_over_range) * rc_img[idx2d_sm];
+                        }
+                        else
+                        {
+                            theta_srm =  theta0 * get_theta_rel_MC(rc_over_range);
+                            rc_eff = get_scat_or_MC(rc_over_range) * rc_img[idx2d_sm];
+                        }
 
                         for (int k = 0; k < dim[2]; k++)
                         {
diff --git a/src/plastimatch/dose/rt_sigma.h b/src/plastimatch/dose/rt_sigma.h
index b09ef0a..1a69706 100644
--- a/src/plastimatch/dose/rt_sigma.h
+++ b/src/plastimatch/dose/rt_sigma.h
@@ -7,11 +7,11 @@
 #include "rt_plan.h"
 #include "rpl_volume.h"
 
-void compute_sigmas(Rt_plan* plan, const Rt_beam* beam, float energy, float* sigma_max, std::string size, int* margins);
-void compute_sigma_pt(Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rpl_volume* ct_vol, Rt_plan* plan, const Rt_beam* beam, float energy);
-float compute_sigma_pt_homo(Rpl_volume* sigma_vol, Rpl_volume* rpl_vol, float energy);
-float compute_sigma_pt_hetero(Rpl_volume* sigma_vol, Rpl_volume* rgl_vol, Rpl_volume* ct_vol, float energy);
-void compute_sigma_source(Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_plan* plan, const Rt_beam* beam, float energy);
-void compute_sigma_range_compensator(Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rt_plan* plan, const Rt_beam* beam, float energy, int* margins);
+void compute_sigmas (const Rt_beam* beam, float energy, float* sigma_max, std::string size, int* margins);
+void compute_sigma_pt (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rpl_volume* ct_vol, const Rt_beam* beam, float energy);
+float compute_sigma_pt_homo (Rpl_volume* sigma_vol, Rpl_volume* rpl_vol, float energy);
+float compute_sigma_pt_hetero (Rpl_volume* sigma_vol, Rpl_volume* rgl_vol, Rpl_volume* ct_vol, float energy);
+void compute_sigma_source (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, const Rt_beam* beam, float energy);
+void compute_sigma_range_compensator (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, const Rt_beam* beam, float energy, int* margins);
 
 #endif
diff --git a/src/plastimatch/dose/rt_spot_map.cxx b/src/plastimatch/dose/rt_spot_map.cxx
new file mode 100755
index 0000000..b5dc209
--- /dev/null
+++ b/src/plastimatch/dose/rt_spot_map.cxx
@@ -0,0 +1,55 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmdose_config.h"
+#include <list>
+#include "rt_spot_map.h"
+
+class Rt_spot_map_private {
+public:
+    std::list<Rt_spot> spot_list;
+};
+
+Rt_spot_map::Rt_spot_map ()
+{
+    d_ptr = new Rt_spot_map_private;
+}
+
+Rt_spot_map::~Rt_spot_map ()
+{
+    delete d_ptr;
+}
+
+void 
+Rt_spot_map::add_spot (
+    float xpos,
+    float ypos,
+    float energy,
+    float sigma,
+    float weight)
+{
+    d_ptr->spot_list.push_back (
+        Rt_spot (xpos, ypos, energy, sigma, weight));
+}
+
+size_t
+Rt_spot_map::num_spots () const
+{
+    return d_ptr->spot_list.size ();
+}
+
+const std::list<Rt_spot>&
+Rt_spot_map::get_spot_list () const
+{
+    return d_ptr->spot_list;
+}
+
+void
+Rt_spot_map::load_spot_map (const std::string& fn)
+{
+}
+
+void
+Rt_spot_map::save_spot_map (const std::string& fn) const
+{
+}
diff --git a/src/plastimatch/dose/rt_spot_map.h b/src/plastimatch/dose/rt_spot_map.h
new file mode 100755
index 0000000..f8a7f2d
--- /dev/null
+++ b/src/plastimatch/dose/rt_spot_map.h
@@ -0,0 +1,43 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _rt_spot_map_h_
+#define _rt_spot_map_h_
+
+#include "plmdose_config.h"
+#include "smart_pointer.h"
+
+class Rt_spot_map_private;
+
+class PLMDOSE_API Rt_spot {
+public:
+    Rt_spot (
+        float xpos, float ypos, float energy, float sigma, float weight)
+        : xpos(xpos), ypos(ypos), energy(energy), sigma(sigma), weight(weight)
+    {}
+public:
+    float xpos;
+    float ypos;
+    float energy;
+    float sigma;
+    float weight;
+};
+
+class PLMDOSE_API Rt_spot_map {
+public:
+    SMART_POINTER_SUPPORT (Rt_spot_map);
+    Rt_spot_map_private *d_ptr;
+public:
+    Rt_spot_map ();
+    ~Rt_spot_map ();
+public:
+    void add_spot (
+        float xpos, float ypos, float energy, float sigma, float weight);
+    size_t num_spots () const;
+    const std::list<Rt_spot>& get_spot_list () const;
+
+    void load_spot_map (const std::string& fn);
+    void save_spot_map (const std::string& fn) const;
+};
+
+#endif
diff --git a/src/plastimatch/dose/wed_parms.h b/src/plastimatch/dose/wed_parms.h
old mode 100644
new mode 100755
index ad03b93..c162d98
--- a/src/plastimatch/dose/wed_parms.h
+++ b/src/plastimatch/dose/wed_parms.h
@@ -6,6 +6,7 @@
 
 #include "plmdose_config.h"
 #include <string>
+#include "plm_int.h"
 
 class PLMDOSE_API Wed_Parms {
 public:
@@ -13,7 +14,6 @@ public:
     ~Wed_Parms ();
 
     bool parse_args (int argc, char** argv);
-    //void parse_group (int argc, char** argv, int line);
 
 private:
     void parse_config (const char* config_fn);
@@ -41,9 +41,6 @@ public:
     std::string output_dew_ct_fn;    /* output: ct in world coordinates */
     std::string output_dew_dose_fn;  /* output: dose in world coordinates */
 
-//    std::string output_ap_fn;        /* output: aperture volume */
-//    std::string output_depth_fn;     /* output: depth volume */
-
     /* [BEAM] */
     bool have_ray_step;
     float ray_step;                  /* Uniform ray step size (mm) */
@@ -53,7 +50,7 @@ public:
 
     /* [APERTURE] */
     float vup[3];
-    int ires[2];
+    plm_long ires[2];
     bool have_ic;
     bool have_ires;
     float ic[2];
diff --git a/src/plastimatch/opencl/CMakeLists.txt b/src/plastimatch/opencl/CMakeLists.txt
old mode 100755
new mode 100644
diff --git a/src/plastimatch/opencl/autotune_opencl.cxx b/src/plastimatch/opencl/autotune_opencl.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/opencl/autotune_opencl.h b/src/plastimatch/opencl/autotune_opencl.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/reconstruct/drr.cxx b/src/plastimatch/reconstruct/drr.cxx
index b843b66..77a17a4 100644
--- a/src/plastimatch/reconstruct/drr.cxx
+++ b/src/plastimatch/reconstruct/drr.cxx
@@ -14,6 +14,7 @@
 #include "drr_cuda.h"
 #include "drr_opencl.h"
 #include "drr_trilin.h"
+#include "file_util.h"
 #include "plm_int.h"
 #include "plm_math.h"
 #include "proj_image.h"
@@ -183,7 +184,11 @@ drr_ray_trace_image (
 
     FILE *details_fp = 0;
     if (options->output_details_fn != "") {
-        details_fp = fopen (options->output_details_fn.c_str(), "w");
+        details_fp = plm_fopen (options->output_details_fn.c_str(), "w");
+        if (!details_fp) {
+            print_and_exit ("Failed to open %s for write\n",
+                options->output_details_fn.c_str());
+        }
     }
 
     /* Compute the drr pixels */
diff --git a/src/plastimatch/reconstruct/drr_opencl.cxx b/src/plastimatch/reconstruct/drr_opencl.cxx
index eeef2ab..5575f6b 100644
--- a/src/plastimatch/reconstruct/drr_opencl.cxx
+++ b/src/plastimatch/reconstruct/drr_opencl.cxx
@@ -97,7 +97,6 @@ drr_opencl_ray_trace_image (
     cl_float4 ocl_nrm, ocl_lower_limit, ocl_upper_limit;
     cl_float ocl_sad;
     cl_int4 ocl_vol_dim;
-    cl_int2 ocl_proj_dim;
 
     /* Copy ic to device (convert from double to float) */
     opencl_idx(ocl_ic,0) = proj->pmat->ic[0];
@@ -146,10 +145,6 @@ drr_opencl_ray_trace_image (
     opencl_idx(ocl_vol_dim,1) = vol->dim[1];
     opencl_idx(ocl_vol_dim,2) = vol->dim[2];
     
-    /* Copy projection image dim (convert from size_t to int) */
-    opencl_idx(ocl_proj_dim,0) = proj->dim[0];
-    opencl_idx(ocl_proj_dim,1) = proj->dim[1];
-    
     /* Set drr kernel arguments */
     opencl_set_kernel_args (
 	&dev_state->ocl_dev, 
diff --git a/src/plastimatch/reconstruct/fdk.cxx b/src/plastimatch/reconstruct/fdk.cxx
old mode 100644
new mode 100755
index 4e09c99..8fb663b
--- a/src/plastimatch/reconstruct/fdk.cxx
+++ b/src/plastimatch/reconstruct/fdk.cxx
@@ -567,7 +567,7 @@ project_volume_onto_image_reference (
 		double ip[3];        /* ip = image position */
 		double s;            /* s = projection of vp onto s axis */
 		vp[0] = (double) (vol->origin[0] + i * vol->spacing[0]);
-		mat43_mult_vec3 (ip, pmat->matrix, vp);  /* ip = matrix * vp */
+		mat43_mult_vec4 (ip, pmat->matrix, vp);  /* ip = matrix * vp */
 		ip[0] = pmat->ic[0] + ip[0] / ip[2];
 		ip[1] = pmat->ic[1] + ip[1] / ip[2];
 		/* Distance on cenral axis from voxel center to source */
diff --git a/src/plastimatch/register/CMakeLists.txt b/src/plastimatch/register/CMakeLists.txt
index c9d4528..1349d30 100644
--- a/src/plastimatch/register/CMakeLists.txt
+++ b/src/plastimatch/register/CMakeLists.txt
@@ -22,57 +22,65 @@ endif ()
 ##  SOURCE FILES
 ##-----------------------------------------------------------------------------
 set (PLMREGISTER_LIBRARY_SRC
-  bspline.cxx
+  bspline.cxx bspline.h
   bspline_loop.txx
-  bspline_landmarks.cxx
+  bspline_landmarks.cxx bspline_landmarks.h
   bspline_gm.cxx bspline_gm.h
   bspline_gm.txx
   bspline_mi.cxx bspline_mi.h
   bspline_mi.txx
-  bspline_mi_hist.cxx
   bspline_mse.cxx bspline_mse.h
   bspline_mse.txx
-  bspline_optimize.cxx
-  bspline_optimize_lbfgsb.cxx
-  bspline_optimize_liblbfgs.cxx
-  bspline_optimize_nlopt.cxx
-  bspline_optimize_steepest.cxx
+  bspline_optimize.cxx bspline_optimize.h
+  bspline_optimize_lbfgsb.cxx bspline_optimize_lbfgsb.h
+  bspline_optimize_liblbfgs.cxx bspline_optimize_liblbfgs.h
+  bspline_optimize_nlopt.cxx bspline_optimize_nlopt.h
+  bspline_optimize_steepest.cxx bspline_optimize_steepest.h
   bspline_parms.cxx bspline_parms.h
   bspline_score.cxx bspline_score.h 
   bspline_stage.cxx bspline_stage.h 
   bspline_state.cxx bspline_state.h 
   bspline_regularize.cxx bspline_regularize.h 
-  bspline_regularize_analytic.cxx
-  bspline_regularize_numeric.cxx
+  bspline_regularize_analytic.cxx bspline_regularize_analytic.h
+  bspline_regularize_numeric.cxx bspline_regularize_numeric.h
   bspline_regularize_semi_analytic.cxx
-  demons.cxx
-  itk_align_center.cxx itk_align_center.h 
-  itk_demons.cxx
-  itk_demons.cxx
-  itk_demons_util.cxx
-  itk_fsf_demons.cxx
-  itk_diff_demons.cxx
-  itk_log_demons.cxx
-  itk_sym_log_demons.cxx
+  demons.cxx demons.h
   demons_cpu.cxx
-  demons_state.cxx
-  gpuit_demons.cxx
-  itk_optimizer.cxx
-  itk_registration.cxx
-  itk_registration_observer.cxx
-  itk_tps.cxx
-  landmark_warp.cxx 
-  process_parms.cxx
-  rbf_cluster.cxx
-  rbf_gauss.cxx
-  rbf_wendland.cxx
+  demons_opencl_p.h
+  demons_state.cxx demons_state.h
+  gpuit_demons.cxx gpuit_demons.h
+  groupwise_parms.cxx groupwise_parms.h
+  histogram.cxx histogram.h
+  itk_align_center.cxx itk_align_center.h 
+  itk_demons.cxx itk_demons.h
+  itk_demons_registration_filter.h
+  itk_demons_util.cxx itk_demons_util.h
+  itk_diff_demons.cxx itk_diff_demons.h
+  itk_fsf_demons.cxx itk_fsf_demons.h
+  itk_log_demons.cxx itk_log_demons.h
+  itk_sym_log_demons.cxx itk_sym_log_demons.h
+  itk_optimizer.cxx itk_optimizer.h
+  itk_registration.cxx itk_registration.h
+  itk_registration_observer.cxx itk_registration_private.h
+  itk_sym_log_demons.h
+  itk_tps.cxx itk_tps.h
+  joint_histogram.cxx joint_histogram.h
+  landmark_warp.cxx landmark_warp.h
+  metric_parms.cxx metric_parms.h 
+  metric_state.cxx metric_state.h
+  process_parms.cxx process_parms.h
+  rbf_cluster.cxx rbf_cluster.h
+  rbf_gauss.cxx rbf_gauss.h
+  rbf_wendland.cxx rbf_wendland.h
   registration.cxx registration.h
-  registration_data.cxx
-  registration_metric_type.cxx registration_metric_type.h
+  registration_data.cxx registration_data.h
   registration_parms.cxx registration_parms.h
   registration_resample.cxx registration_resample.h 
-  shared_parms.cxx
-  stage_parms.cxx
+  registration_similarity_data.h
+  registration_util.cxx registration_util.h 
+  shared_parms.cxx shared_parms.h
+  similarity_metric_type.cxx similarity_metric_type.h
+  stage_parms.cxx stage_parms.h
   translation_grid_search.cxx translation_grid_search.h 
   translation_mi.cxx translation_mi.h 
   translation_mse.cxx translation_mse.h 
diff --git a/src/plastimatch/register/bspline.cxx b/src/plastimatch/register/bspline.cxx
index 4a52dab..7bb8093 100644
--- a/src/plastimatch/register/bspline.cxx
+++ b/src/plastimatch/register/bspline.cxx
@@ -38,7 +38,6 @@
 #include "bspline_interpolate.h"
 #include "bspline_landmarks.h"
 #include "bspline_mi.h"
-#include "bspline_mi_hist.h"
 #include "bspline_mse.h"
 #include "bspline_optimize.h"
 #include "bspline_parms.h"
@@ -48,6 +47,7 @@
 #include "delayload.h"
 #include "file_util.h"
 #include "interpolate_macros.h"
+#include "joint_histogram.h"
 #include "logfile.h"
 #include "plm_math.h"
 #include "plm_timer.h"
@@ -68,7 +68,8 @@
 // Author: James Shackleford
 // Data: July 30th, 2009
 ////////////////////////////////////////////////////////////////////////////////
-int* calc_offsets(int* tile_dims, int* cdims)
+int*
+calc_offsets (int* tile_dims, int* cdims)
 {
     int vox_per_tile = (tile_dims[0] * tile_dims[1] * tile_dims[2]);
     int pad = 32 - (vox_per_tile % 32);
@@ -99,7 +100,8 @@ int* calc_offsets(int* tile_dims, int* cdims)
 // Author: James Shackleford
 // Data: July 13th, 2009
 ////////////////////////////////////////////////////////////////////////////////
-void find_knots (
+void
+find_knots (
     plm_long* knots, 
     plm_long tile_num, 
     plm_long* rdims, 
@@ -117,11 +119,6 @@ void find_knots (
     tile_loc[0] = tile_num % num_tiles_x;
     tile_loc[1] = ((tile_num - tile_loc[0]) / num_tiles_x) % num_tiles_y;
     tile_loc[2] = ((((tile_num - tile_loc[0]) / num_tiles_x) / num_tiles_y) % num_tiles_z);
-    /*
-      tile_loc[0] = tile_num % rdims[0];
-      tile_loc[1] = ((tile_num - tile_loc[0]) / rdims[0]) % rdims[1];
-      tile_loc[2] = ((((tile_num - tile_loc[0]) / rdims[0]) / rdims[1]) % rdims[2]);
-    */
 
     // Tiles do not start on the edges of the grid, so we
     // push them to the center of the control grid.
@@ -131,17 +128,17 @@ void find_knots (
 
     // Find 64 knots' [x,y,z] coordinates
     // and convert into a linear knot index
-    for (k = -1; k < 3; k++)
-        for (j = -1; j < 3; j++)
+    for (k = -1; k < 3; k++) {
+        for (j = -1; j < 3; j++) {
             for (i = -1; i < 3; i++)
             {
                 knots[idx++] = (cdims[0]*cdims[1]*(tile_loc[2]+k)) + (cdims[0]*(tile_loc[1]+j)) + (tile_loc[0]+i);
             }
-
+        }
+    }
 }
 
 
-
 /* -----------------------------------------------------------------------
    Debugging routines
    ----------------------------------------------------------------------- */
@@ -198,10 +195,10 @@ bspline_save_debug_state (
         fn = parms->debug_dir + "/" + buf;
         bxf->save (fn.c_str());
 
-        if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
+        if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) {
             sprintf (buf, "%02d_", parms->debug_stage);
             fn = parms->debug_dir + "/" + buf;
-            bst->mi_hist->dump_hist (bst->feval, fn);
+            bst->get_mi_hist()->dump_hist (bst->feval, fn);
         }
     }
 }
@@ -297,9 +294,9 @@ bspline_condense_smetric_grad (float* cond_x, float* cond_y, float* cond_z,
 
     for (kidx=0; kidx < bxf->num_knots; kidx++) {
         for (sidx=0; sidx<64; sidx++) {
-            ssd->smetric_grad[3*kidx + 0] += cond_x[64*kidx + sidx];
-            ssd->smetric_grad[3*kidx + 1] += cond_y[64*kidx + sidx];
-            ssd->smetric_grad[3*kidx + 2] += cond_z[64*kidx + sidx];
+            ssd->curr_smetric_grad[3*kidx + 0] += cond_x[64*kidx + sidx];
+            ssd->curr_smetric_grad[3*kidx + 1] += cond_y[64*kidx + sidx];
+            ssd->curr_smetric_grad[3*kidx + 2] += cond_z[64*kidx + sidx];
         }
     }
 }
@@ -308,7 +305,7 @@ static void
 logfile_print_score (float score)
 {
     if (score < 10. && score > -10.) {
-        logfile_printf (" %1.8f ", score);
+        logfile_printf (" %1.7f ", score);
     } else {
         logfile_printf (" %9.3f ", score);
     }
@@ -338,45 +335,56 @@ report_score (
     }
 
     /* Compute total time */
+    double total_smetric_time = 0;
     double total_time = 0;
-    std::vector<double>::const_iterator it_time = ssd->time_smetric.begin();
-    while (it_time != ssd->time_smetric.end()) {
-        total_time += *it_time;
-        ++it_time;
+    plm_long hack_num_vox = 0;
+    std::vector<Metric_score>::const_iterator it_mr 
+        = ssd->metric_record.begin();
+    while (it_mr != ssd->metric_record.end()) {
+        total_time += it_mr->time;
+        if (hack_num_vox == 0) {
+            hack_num_vox = it_mr->num_vox;
+        }
+        ++it_mr;
     }
+    total_smetric_time = total_time;
     total_time += ssd->time_rmetric;
     
     /* First line, iterations, score, misc stats */
     logfile_printf ("[%2d,%3d] ", bst->it, bst->feval);
-    if (reg_parms->lambda > 0 || blm->num_landmarks > 0
-        || parms->metric_type.size() > 1)
+    if (reg_parms->lambda > 0
+        || blm->num_landmarks > 0
+        || bst->similarity_data.size() > 1)
     {
         logfile_printf ("SCORE ");
     } else {
-        logfile_printf ("%-6s", registration_metric_type_string (
-                parms->metric_type[0]));
+        logfile_printf ("%-6s", 
+            bst->similarity_data.front()->metric_string());
     }
-    logfile_print_score (ssd->score);
+    logfile_print_score (ssd->total_score);
     logfile_printf (
         "NV %6d GM %9.3f GN %9.3g [ %9.3f s ]\n",
-        ssd->num_vox, ssd_grad_mean, sqrt (ssd_grad_norm), total_time);
+        hack_num_vox, ssd_grad_mean, sqrt (ssd_grad_norm), total_time);
     
     /* Second line */
-    if (reg_parms->lambda > 0 || blm->num_landmarks > 0
-        || parms->metric_type.size() > 1)
+    if (reg_parms->lambda > 0
+        || blm->num_landmarks > 0
+        || bst->similarity_data.size() > 1)
     {
         logfile_printf ("         ");
-        /* Part 1 - smetric(s) */   
-        std::vector<float>::const_iterator it_sm = ssd->smetric.begin();
-        std::vector<Registration_metric_type>::const_iterator it_st
-            = parms->metric_type.begin();
-        while (it_sm != ssd->smetric.end()) {
-            logfile_printf ("%-6s",
-                registration_metric_type_string (*it_st));
-            logfile_print_score (*it_sm);
-            ++it_sm, ++it_st;
+        /* Part 1 - smetric(s) */
+        /* GCS FIX: It should not be that one of these is a list 
+           and the other is a vector. */
+        std::vector<Metric_score>::const_iterator it_mr 
+            = ssd->metric_record.begin();
+        std::list<Metric_state::Pointer>::const_iterator it_st
+            = bst->similarity_data.begin();
+        while (it_mr != ssd->metric_record.end()) {
+            logfile_printf ("%-6s", (*it_st)->metric_string());
+            logfile_print_score (it_mr->score);
+            ++it_mr, ++it_st;
         }
-        if (ssd->smetric.size() > 1
+        if (ssd->metric_record.size() > 1
             && (reg_parms->lambda > 0 || blm->num_landmarks > 0))
         {
             logfile_printf ("\n");
@@ -396,7 +404,7 @@ report_score (
             /* Part 4 - timing */
             if (reg_parms->lambda > 0) {
                 logfile_printf ("[ %9.3f | %9.3f ]", 
-                    ssd->time_smetric[0], ssd->time_rmetric);
+                    total_smetric_time, ssd->time_rmetric);
             }
         }
         logfile_printf ("\n");
@@ -416,37 +424,48 @@ bspline_score (Bspline_optimize *bod)
     /* Zero out the score for this iteration */
     bst->ssd.reset_score ();
 
-    /* Compute similarity metrics */
-    std::vector<Registration_metric_type>::const_iterator it_metric
-        = parms->metric_type.begin();
-    std::vector<float>::const_iterator it_lambda
-        = parms->metric_lambda.begin();
+    /* Compute similarity metric.  This is done for each metric 
+       and each similarity metric within each image plane. */
+    std::list<Metric_state::Pointer>::const_iterator it_sd;
     bst->sm = 0;
-    while (it_metric != parms->metric_type.end()
-        && it_lambda != parms->metric_lambda.end())
+    for (it_sd = bst->similarity_data.begin();
+         it_sd != bst->similarity_data.end(); ++it_sd)
     {
+        bst->set_metric_state (*it_sd);
+        bst->initialize_similarity_images ();
         Plm_timer timer;
         timer.start ();
-        bst->ssd.smetric.push_back (0.f);
-        if (*it_metric == REGISTRATION_METRIC_MSE) {
+
+        switch ((*it_sd)->metric_type) {
+        case SIMILARITY_METRIC_DMAP:
+        case SIMILARITY_METRIC_MSE:
             bspline_score_mse (bod);
-        }
-        else if (*it_metric == REGISTRATION_METRIC_MI_MATTES) {
+            break;
+        case SIMILARITY_METRIC_MI_MATTES:
             bspline_score_mi (bod);
-        }
-        else if (*it_metric == REGISTRATION_METRIC_GM) {
+            break;
+        case SIMILARITY_METRIC_GM:
             bspline_score_gm (bod);
-        }
-        else {
-            print_and_exit ("Unknown similarity metric in bspline_score()\n");
+            break;
+        default:
+            print_and_exit (
+                "Unknown similarity metric in bspline_score()\n");
+            break;
         }
 
-        bst->ssd.accumulate_grad (*it_lambda);
-
-        bst->ssd.time_smetric.push_back (timer.report ());
+        bst->ssd.metric_record.push_back (
+            Metric_score (bst->ssd.curr_smetric, timer.report (),
+                bst->ssd.curr_num_vox));
+#if defined (commentout)
+        printf (">> %f + %f * %f ->",
+            bst->ssd.total_score, (*it_sd)->metric_lambda, 
+            bst->ssd.curr_smetric);
+#endif
+        bst->ssd.accumulate ((*it_sd)->metric_lambda);
+#if defined (commentout)
+        printf (" %f\n", bst->ssd.total_score);
+#endif
         bst->sm ++;
-        ++it_metric;
-        ++it_lambda;
     }
 
     /* Compute regularization */
@@ -459,10 +478,10 @@ bspline_score (Bspline_optimize *bod)
         bspline_landmarks_score (parms, bst, bxf);
     }
 
-    /* Compute total score */
-    bst->ssd.score = bst->ssd.smetric[0] + reg_parms->lambda * bst->ssd.rmetric;
+    /* Update total score with regularization and landmarks */
+    bst->ssd.total_score += reg_parms->lambda * bst->ssd.rmetric;
     if (blm->num_landmarks > 0) {
-        bst->ssd.score += blm->landmark_stiffness * bst->ssd.lmetric;
+        bst->ssd.total_score += blm->landmark_stiffness * bst->ssd.lmetric;
     }
 
     /* Report results of this iteration */
diff --git a/src/plastimatch/register/bspline.h b/src/plastimatch/register/bspline.h
index 6c30b0f..38472cd 100644
--- a/src/plastimatch/register/bspline.h
+++ b/src/plastimatch/register/bspline.h
@@ -8,7 +8,7 @@
 #include "plm_int.h"
 #include <string>
 
-class Bspline_mi_hist_set;
+class Joint_histogram;
 class Bspline_optimize;
 class Bspline_parms;
 class Bspline_score;
@@ -33,7 +33,6 @@ PLMREGISTER_API void bspline_save_debug_state (
     Bspline_state *bst, 
     Bspline_xform* bxf
 );
-void dump_xpm_hist (Bspline_mi_hist_set* mi_hist, char* file_base, int iter);
 void bspline_condense_smetric_grad (
     float* cond_x, float* cond_y, float* cond_z,
     Bspline_xform* bxf,
diff --git a/src/plastimatch/register/bspline_gm.h b/src/plastimatch/register/bspline_gm.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/register/bspline_gm.txx b/src/plastimatch/register/bspline_gm.txx
index a14c55c..33d9660 100755
--- a/src/plastimatch/register/bspline_gm.txx
+++ b/src/plastimatch/register/bspline_gm.txx
@@ -15,8 +15,8 @@ public:
 public:
     Bspline_gm_k (Bspline_optimize *bod)
     {
-        Bspline_parms *parms = bod->get_bspline_parms ();
-        Volume *moving_grad = parms->moving_grad;
+        Bspline_state *bst = bod->get_bspline_state ();
+        Volume *moving_grad = bst->moving_grad;
         m_grad = (float*) moving_grad->img;
         score_acc = 0.;
     }
@@ -70,7 +70,7 @@ public:
 
         /* Update cost function gradient */
         ssd->update_smetric_grad_b (bxf, pidx, qidx, dc_dv);
-        ssd->num_vox++;
+        ssd->curr_num_vox++;
     }
 };
 
diff --git a/src/plastimatch/register/bspline_loop.txx b/src/plastimatch/register/bspline_loop.txx
index 0236260..4f04de6 100755
--- a/src/plastimatch/register/bspline_loop.txx
+++ b/src/plastimatch/register/bspline_loop.txx
@@ -38,10 +38,10 @@ bspline_loop_voxel_serial (
     Bspline_xform *bxf = bod->get_bspline_xform ();
     Bspline_score* ssd = &bst->ssd;
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *fixed_roi  = parms->fixed_roi;
-    Volume *moving_roi = parms->moving_roi;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *fixed_roi  = bst->fixed_roi;
+    Volume *moving_roi = bst->moving_roi;
 
     plm_long fijk[3], fidx;     /* Indices within fixed image (vox) */
     float mijk[3];              /* Indices within moving image (vox) */
@@ -164,10 +164,10 @@ bspline_loop_tile_serial (
     Bspline_xform *bxf = bod->get_bspline_xform ();
     Bspline_score* ssd = &bst->ssd;
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *fixed_roi  = parms->fixed_roi;
-    Volume *moving_roi = parms->moving_roi;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *fixed_roi  = bst->fixed_roi;
+    Volume *moving_roi = bst->moving_roi;
 
     float* f_img = (float*) fixed->img;
     float* m_img = (float*) moving->img;
@@ -207,8 +207,6 @@ bspline_loop_tile_serial (
     // Serial across tiles
     plm_long pidx;
     LOOP_THRU_VOL_TILES (pidx, bxf) {
-        int rc;
-
         int ijk_tile[3];
         plm_long q[3];
 
@@ -217,14 +215,9 @@ bspline_loop_tile_serial (
         float mijk[3];              /* Indices within moving image (vox) */
         float mxyz[3];              /* Position within moving image (mm) */
         plm_long mijk_f[3], midx_f; /* Floor */
-        plm_long mijk_r[3], midx_r; /* Round */
-
+        plm_long mijk_r[3];         /* Round */
         float dxyz[3];
-
         float li_1[3], li_2[3];
-        float m_val, diff;
-    
-        float dc_dv[3];
 
         float sets_x[64];
         float sets_y[64];
@@ -294,7 +287,6 @@ bspline_loop_tile_serial (
 
                     // Find linear indices for moving image
                     midx_f = volume_index (moving->dim, mijk_f);
-                    midx_r = volume_index (moving->dim, mijk_r);
 
                     /* Run the target function */
                     bspline_loop_user.loop_function (
@@ -357,10 +349,10 @@ bspline_loop_tile_parallel (
     Bspline_xform *bxf = bod->get_bspline_xform ();
     Bspline_score* ssd = &bst->ssd;
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *fixed_roi  = parms->fixed_roi;
-    Volume *moving_roi = parms->moving_roi;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *fixed_roi  = bst->fixed_roi;
+    Volume *moving_roi = bst->moving_roi;
 
     float* f_img = (float*) fixed->img;
     float* m_img = (float*) moving->img;
diff --git a/src/plastimatch/register/bspline_mi.cxx b/src/plastimatch/register/bspline_mi.cxx
index 5091f60..e453d8a 100644
--- a/src/plastimatch/register/bspline_mi.cxx
+++ b/src/plastimatch/register/bspline_mi.cxx
@@ -20,19 +20,18 @@
 #include "bspline_macros.h"
 #include "bspline_mi.h"
 #include "bspline_mi.txx"
-#include "bspline_mi_hist.h"
 #include "bspline_optimize.h"
 #include "bspline_parms.h"
 #include "bspline_state.h"
 #include "file_util.h"
 #include "interpolate.h"
 #include "interpolate_macros.h"
+#include "joint_histogram.h"
 #include "logfile.h"
 #include "mha_io.h"
 #include "plm_math.h"
 #include "volume_macros.h"
 #include "volume.h"
-#include "xpm.h"
 
 /* Some neat debug facilities
  *   Will probably move these somewhere more appropriate soon
@@ -190,7 +189,7 @@ bspline_mi_hist_lookup (
     long m_idxs[2],     /* Output: Moving marginal indices */
     long f_idxs[1],     /* Output: Fixed marginal indices */
     float fxs[2],       /* Output: Fraction contribution at indices */
-    Bspline_mi_hist_set* mi_hist,   /* Input:  The histogram */
+    Joint_histogram* mi_hist,   /* Input:  The histogram */
     float f_val,        /* Input:  Intensity of fixed image */
     float m_val             /* Input:  Intensity of moving image */
 )
@@ -252,7 +251,7 @@ bspline_mi_hist_lookup (
     based on m_val, but one bin based on f_val. */
 inline void
 bspline_mi_hist_add (
-    Bspline_mi_hist_set* mi_hist,   /* The histogram */
+    Joint_histogram* mi_hist,   /* The histogram */
     float f_val,        /* Intensity of fixed image */
     float m_val,        /* Intensity of moving image */
     float amt               /* How much to add to histogram */
@@ -281,7 +280,7 @@ bspline_mi_hist_add (
 
 /* This algorithm uses a un-normalized score. */
 static float
-mi_hist_score_omp (Bspline_mi_hist_set* mi_hist, int num_vox)
+mi_hist_score_omp (Joint_histogram* mi_hist, int num_vox)
 {
     double* f_hist = mi_hist->f_hist;
     double* m_hist = mi_hist->m_hist;
@@ -354,221 +353,12 @@ compute_dS_dP (
     return dS_dP;
 }
 
-void dump_xpm_hist (Bspline_mi_hist_set* mi_hist, char* file_base, int iter)
-{
-    int z;
-    char c;
-
-    // Graph Properties
-    int graph_offset_x = 10;
-    int graph_offset_y = 10;
-    int graph_padding = 20;
-    int graph_bar_height = 100;
-    int graph_bar_width = 5;
-    int graph_bar_spacing = (int)((float)graph_bar_width * (7.0/5.0));
-    plm_long graph_color_levels = 22;
-
-    //  int fixed_bar_height;   // max bar height (pixels)
-    //  int moving_bar_height;
-    plm_long joint_color;
-
-    float fixed_scale;  // pixels per amt
-    float moving_scale;
-    float joint_scale;
-
-    float moving_max_val=0; 
-    float fixed_max_val=0;
-    float joint_max_val=0;
-
-    int fixed_total_width = mi_hist->fixed.bins * graph_bar_spacing;
-    int moving_total_width = mi_hist->moving.bins * graph_bar_spacing;
-
-    int graph_moving_x_pos = graph_offset_x + graph_bar_height + graph_padding;
-    int graph_moving_y_pos = graph_offset_y + fixed_total_width + graph_padding + graph_bar_height;
-
-    int graph_fixed_x_pos = graph_offset_x;
-    int graph_fixed_y_pos = graph_offset_y + fixed_total_width;
-
-    int border_padding = 5;
-    int border_width = moving_total_width + 2*border_padding;
-    int border_height = fixed_total_width + 2*border_padding;
-    int border_x_pos = graph_moving_x_pos - border_padding;
-    int border_y_pos = graph_offset_y - border_padding + (int)((float)graph_bar_width * (2.0/5.0));
-
-    int canvas_width = 2*graph_offset_x + graph_bar_height + moving_total_width + graph_padding;
-    int canvas_height = 2*graph_offset_y + graph_bar_height + fixed_total_width + graph_padding;
-    
-    double *m_hist = mi_hist->m_hist;
-    double *f_hist = mi_hist->f_hist;
-    double *j_hist = mi_hist->j_hist;
-    
-    char filename[20];
-
-    sprintf(filename, "%s_%04i.xpm", file_base, iter);
-
-    // ----------------------------------------------
-    // Find max value for fixed
-    for(plm_long i=0; i<mi_hist->fixed.bins; i++)
-        if (f_hist[i] > fixed_max_val)
-            fixed_max_val = f_hist[i];
-    
-    // Find max value for moving
-    for(plm_long i=0; i<mi_hist->moving.bins; i++)
-        if (m_hist[i] > moving_max_val)
-            moving_max_val = m_hist[i];
-    
-    // Find max value for joint
-    // (Ignoring bin 0)
-    for(plm_long j=0; j<mi_hist->fixed.bins; j++) {
-        for(plm_long i=0; i<mi_hist->moving.bins; i++) {
-            if ( (i > 0) && (j > 1) )
-                if (j_hist[j*mi_hist->moving.bins + i] > joint_max_val)
-                    joint_max_val = j_hist[j*mi_hist->moving.bins + i];
-        }
-    }
-
-
-    // Generate scaling factors
-    fixed_scale = (float)graph_bar_height / fixed_max_val;
-    moving_scale = (float)graph_bar_height / moving_max_val;
-    joint_scale = (float)graph_color_levels / joint_max_val;
-    // ----------------------------------------------
-
-
-    
-    // ----------------------------------------------
-    // Pull out a canvas and brush!
-    Xpm_canvas* xpm = new Xpm_canvas (canvas_width, canvas_height, 1);
-    Xpm_brush* brush = new Xpm_brush;
-    
-    // setup the palette
-    xpm->add_color ('a', 0xFFFFFF);    // white
-    xpm->add_color ('b', 0x000000);    // black
-    xpm->add_color ('z', 0xFFCC00);    // orange
-
-    // generate a nice BLUE->RED gradient
-    c = 'c';
-    z = 0x0000FF;
-    for (plm_long i=0; i<(graph_color_levels+1); i++)
-    {
-        xpm->add_color (c, z);
-
-        z -= 0x00000B;      // BLUE--
-        z += 0x0B0000;      //  RED++
-
-        c = (char)((int)c + 1); // LETTER++
-    }
-
-    // Prime the XPM Canvas
-    xpm->prime ('a');
-    // ----------------------------------------------
-    
-
-    printf("Drawing Histograms... ");
-
-    
-    /* Generate Moving Histogram */
-    brush->set_type (XPM_BOX);
-    brush->set_color ('b');
-    brush->set_pos (graph_moving_x_pos, graph_moving_y_pos);
-    brush->set_width (graph_bar_width);
-    brush->set_height (0);
-
-    int tmp_h;
-    for(plm_long i=0; i<mi_hist->moving.bins; i++)
-    {
-        tmp_h = (int)(m_hist[i] * moving_scale);
-        brush->set_height (tmp_h);
-        brush->set_y (graph_moving_y_pos - tmp_h);
-        xpm->draw (brush);
-        brush->inc_x (graph_bar_spacing);
-    }
-
-    
-    /* Generate Fixed Histogram */
-    brush->set_type (XPM_BOX);
-    brush->set_color ('b');
-    brush->set_pos (graph_fixed_x_pos, graph_fixed_y_pos);
-    brush->set_width (0);
-    brush->set_height (graph_bar_width);
-
-    for (plm_long i=0; i<mi_hist->fixed.bins; i++)
-    {
-        brush->set_width ((int)(f_hist[i] * fixed_scale));
-        xpm->draw (brush);
-        brush->inc_x ((-1)*graph_bar_spacing);
-    }
-
-
-    /* Generate Joint Histogram */
-    brush->set_type (XPM_BOX);
-    brush->set_color ('b');
-    brush->set_pos (graph_moving_x_pos, graph_fixed_y_pos);
-    brush->set_width (graph_bar_width);
-    brush->set_height (graph_bar_width);
-
-    z = 0;
-    for(plm_long j=0; j<mi_hist->fixed.bins; j++) {
-        for(plm_long i=0; i<mi_hist->moving.bins; i++) {
-            joint_color = (size_t)(j_hist[z++] * joint_scale);
-            if (joint_color > 0) {
-                // special handling for bin 0
-                if (joint_color > graph_color_levels) {
-                    //  printf ("Clamp @ P(%i,%i)\n", i, j);
-                    //  brush.color = (char)(graph_color_levels + 99);
-                    brush->set_color ('z');
-                } else {
-                    brush->set_color ((char)(joint_color + 99));
-                }
-            } else {
-                brush->set_color ('a');
-            }
-            xpm->draw (brush);     
-            brush->inc_x (graph_bar_spacing);
-        }
-        // get ready to render new row
-        brush->set_x (graph_moving_x_pos);
-        brush->inc_y ((-1)*graph_bar_spacing);
-    }
-
-    /* Generate Joint Histogram Border */
-    brush->set_type (XPM_BOX); // top
-    brush->set_color ('b');
-    brush->set_pos (border_x_pos, border_y_pos);
-    brush->set_width (border_width);
-    brush->set_height (1);
-    xpm->draw (brush);
-
-    brush->set_width (1); // left
-    brush->set_height (border_height);
-    xpm->draw (brush);
-
-    brush->set_width (border_width); // bottom
-    brush->set_height (1);
-    brush->inc_y (border_height);
-    xpm->draw (brush);
-
-    brush->set_width (1); // right
-    brush->set_height (border_height);
-    brush->set_pos (border_width, border_y_pos);
-    xpm->draw (brush);
-
-    printf("done.\n");
-    
-    // Write to file
-    xpm->write (filename);
-
-    delete xpm;
-    delete brush; 
-}
-
-
 /* Use 1 histogram per thread so we are
  * thread safe when employing multi-core */
 #if (OPENMP_FOUND)
 static inline void
 bspline_mi_hist_add_pvi_8_omp_v2 (
-    Bspline_mi_hist_set* mi_hist, 
+    Joint_histogram* mi_hist, 
     double* f_hist_omp,
     double* m_hist_omp,
     double* j_hist_omp,
@@ -643,7 +433,7 @@ bspline_mi_hist_add_pvi_8_omp_v2 (
 #if (OPENMP_FOUND)
 static inline void
 bspline_mi_hist_add_pvi_8_omp_crits (
-    Bspline_mi_hist_set* mi_hist, 
+    Joint_histogram* mi_hist, 
     Volume *fixed, 
     Volume *moving, 
     int fidx, 
@@ -723,7 +513,7 @@ bspline_mi_hist_add_pvi_8_omp_crits (
 #if (OPENMP_FOUND)
 static inline void
 bspline_mi_hist_add_pvi_8_omp (
-    Bspline_mi_hist_set* mi_hist, 
+    Joint_histogram* mi_hist, 
     Volume *fixed, 
     Volume *moving, 
     int fidx, 
@@ -806,7 +596,7 @@ bspline_mi_hist_add_pvi_8_omp (
 #if defined (commentout)
 static inline void
 bspline_mi_hist_add_pvi_6 (
-    Bspline_mi_hist_set* mi_hist, 
+    Joint_histogram* mi_hist, 
     Volume *fixed, 
     Volume *moving, 
     int fidx, 
@@ -891,7 +681,7 @@ bspline_mi_hist_add_pvi_6 (
 static inline void
 bspline_mi_pvi_8_dc_dv (
     float dc_dv[3],                /* Output */
-    Bspline_mi_hist_set* mi_hist,      /* Input */
+    Joint_histogram* mi_hist,      /* Input */
     Bspline_state *bst,            /* Input */
     Volume *fixed,                 /* Input */
     Volume *moving,                /* Input */
@@ -980,7 +770,7 @@ bspline_mi_pvi_8_dc_dv (
         idx_jbin = offset_fbin + idx_mbin;
         if (j_hist[idx_jbin] > 0.0001) {
             dS_dP = logf((num_vox_f * j_hist[idx_jbin]) 
-                / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->smetric[0];
+                / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
             dc_dv[0] -= dw[3*idx_pv+0] * dS_dP;
             dc_dv[1] -= dw[3*idx_pv+1] * dS_dP;
             dc_dv[2] -= dw[3*idx_pv+2] * dS_dP;
@@ -1006,7 +796,7 @@ bspline_mi_pvi_8_dc_dv (
 static inline void
 bspline_mi_pvi_6_dc_dv (
     float dc_dv[3],                /* Output */
-    Bspline_mi_hist_set* mi_hist,      /* Input */
+    Joint_histogram* mi_hist,      /* Input */
     Bspline_state *bst,            /* Input */
     Volume *fixed,                 /* Input */
     Volume *moving,                /* Input */
@@ -1042,7 +832,7 @@ bspline_mi_pvi_6_dc_dv (
         mkqs, fzqs);
 
     /* PARTIAL VALUE INTERPOLATION - 6 neighborhood */
-    float smetric = ssd->smetric[0];
+    float smetric = ssd->curr_smetric;
     midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1];
     bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, 
         mi_hist, f_img[fidx], m_img[midx_f]);
@@ -1121,11 +911,11 @@ bspline_score_i_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     long pidx;
     float num_vox_f;
 
@@ -1256,14 +1046,14 @@ bspline_score_i_mi (
         if (f_hist[i] > f_hist[mi_hist->fixed.big_bin]) {
             mi_hist->fixed.big_bin = i;
         }
-        ssd->num_vox += f_hist[i];
+        ssd->curr_num_vox += f_hist[i];
     }
 
     /* Fill in the missing histogram bin */
     for (plm_long i=0; i<mi_hist->moving.bins; i++) {
         mhis += m_hist[i];
     }
-    m_hist[mi_hist->moving.big_bin] = (double)ssd->num_vox - mhis;
+    m_hist[mi_hist->moving.big_bin] = (double) ssd->curr_num_vox - mhis;
 
 
     /* Look for the biggest moving histogram bin */
@@ -1282,7 +1072,7 @@ bspline_score_i_mi (
             jhis += j_hist[j*mi_hist->moving.bins + i];
         }
     }
-    j_hist[mi_hist->joint.big_bin] = (double)ssd->num_vox - jhis;
+    j_hist[mi_hist->joint.big_bin] = (double) ssd->curr_num_vox - jhis;
 
     
     /* Look for the biggest joint histogram bin */
@@ -1324,8 +1114,8 @@ bspline_score_i_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist_score_omp (mi_hist, ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute Gradient (Parallel across tiles) */
 #pragma omp parallel for
@@ -1424,7 +1214,7 @@ bspline_score_i_mi (
     }
 #endif
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
 }
 #endif
 
@@ -1445,11 +1235,11 @@ bspline_score_h_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     float diff;
     float* f_img = (float*) fixed->img;
     float* m_img = (float*) moving->img;
@@ -1480,8 +1270,8 @@ bspline_score_h_mi (
     float* cond_y = (float*)malloc(cond_size);
     float* cond_z = (float*)malloc(cond_size);
 
-    Volume* fixed_roi  = parms->fixed_roi;
-    Volume* moving_roi = parms->moving_roi;
+    Volume* fixed_roi  = bst->fixed_roi;
+    Volume* moving_roi = bst->moving_roi;
 
 #if 0
     Volume* dbg_vol = volume_clone_empty (moving);
@@ -1563,7 +1353,7 @@ bspline_score_h_mi (
                 /* Compute intensity difference */
                 diff = m_val - f_img[fidx];
                 mse_score += diff * diff;
-                ssd->num_vox ++;
+                ssd->curr_num_vox ++;
 
             } /* LOOP_THRU_ROI_X */
         } /* LOOP_THRU_ROI_Y */
@@ -1580,8 +1370,8 @@ bspline_score_h_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist_score_omp (mi_hist, ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute Gradient (Parallel across tiles) */
 #pragma omp parallel for
@@ -1696,7 +1486,7 @@ bspline_score_h_mi (
         fclose (fp);
     }
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
     if (parms->debug) {
         printf ("<< MSE %3.3f >>\n", mse_score);
     }
@@ -1718,11 +1508,11 @@ bspline_score_g_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     float diff;
     float* f_img = (float*) fixed->img;
     float* m_img = (float*) moving->img;
@@ -1815,7 +1605,7 @@ bspline_score_g_mi (
                 /* Compute intensity difference */
                 diff = m_val - f_img[fidx];
                 mse_score += diff * diff;
-                ssd->num_vox ++;
+                ssd->curr_num_vox ++;
 
             } /* LOOP_THRU_ROI_X */
         } /* LOOP_THRU_ROI_Y */
@@ -1827,8 +1617,8 @@ bspline_score_g_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist_score_omp (mi_hist, ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute Gradient (Parallel across tiles) */
 #pragma omp parallel for
@@ -1937,7 +1727,7 @@ bspline_score_g_mi (
     }
 #endif
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
     if (parms->debug) {
         printf ("<< MSE %3.3f >>\n", mse_score);
     }
@@ -1966,11 +1756,11 @@ bspline_score_f_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     int pidx;
     float num_vox_f;
 
@@ -2072,14 +1862,14 @@ bspline_score_f_mi (
         if (f_hist[i] > f_hist[mi_hist->fixed.big_bin]) {
             mi_hist->fixed.big_bin = i;
         }
-        ssd->num_vox += f_hist[i];
+        ssd->curr_num_vox += f_hist[i];
     }
 
     /* Fill in the missing histogram bin */
     for(plm_long i=0; i<mi_hist->moving.bins; i++) {
         mhis += m_hist[i];
     }
-    m_hist[mi_hist->moving.big_bin] = (double)ssd->num_vox - mhis;
+    m_hist[mi_hist->moving.big_bin] = (double) ssd->curr_num_vox - mhis;
 
 
     /* Look for the biggest moving histogram bin */
@@ -2096,7 +1886,7 @@ bspline_score_f_mi (
             jhis += j_hist[j*mi_hist->moving.bins + i];
         }
     }
-    j_hist[mi_hist->joint.big_bin] = (double)ssd->num_vox - jhis;
+    j_hist[mi_hist->joint.big_bin] = (double) ssd->curr_num_vox - jhis;
 
     
     /* Look for the biggest joint histogram bin */
@@ -2134,8 +1924,8 @@ bspline_score_f_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist_score_omp (mi_hist, ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute Gradient (Parallel across tiles) */
 #pragma omp parallel for
@@ -2234,7 +2024,7 @@ bspline_score_f_mi (
     }
 #endif
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
 }
 #endif
 
@@ -2258,11 +2048,11 @@ bspline_score_e_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     long pidx;
     float num_vox_f;
 
@@ -2389,14 +2179,14 @@ bspline_score_e_mi (
         if (f_hist[i] > f_hist[mi_hist->fixed.big_bin]) {
             mi_hist->fixed.big_bin = i;
         }
-        ssd->num_vox += f_hist[i];
+        ssd->curr_num_vox += f_hist[i];
     }
 
     /* Fill in the missing histogram bin */
     for (plm_long i=0; i<mi_hist->moving.bins; i++) {
         mhis += m_hist[i];
     }
-    m_hist[mi_hist->moving.big_bin] = (double)ssd->num_vox - mhis;
+    m_hist[mi_hist->moving.big_bin] = (double) ssd->curr_num_vox - mhis;
 
 
     /* Look for the biggest moving histogram bin */
@@ -2415,7 +2205,7 @@ bspline_score_e_mi (
             jhis += j_hist[j*mi_hist->moving.bins + i];
         }
     }
-    j_hist[mi_hist->joint.big_bin] = (double)ssd->num_vox - jhis;
+    j_hist[mi_hist->joint.big_bin] = (double) ssd->curr_num_vox - jhis;
 
     
     /* Look for the biggest joint histogram bin */
@@ -2457,8 +2247,8 @@ bspline_score_e_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist_score_omp (mi_hist, ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute Gradient (Parallel across tiles) */
 #pragma omp parallel for
@@ -2573,7 +2363,7 @@ bspline_score_e_mi (
     }
 #endif
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
 }
 #endif
 
@@ -2593,11 +2383,11 @@ bspline_score_d_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     plm_long rijk[3];
     float diff;
     float* f_img = (float*) fixed->img;
@@ -2714,7 +2504,7 @@ bspline_score_d_mi (
                 /* Compute intensity difference */
                 diff = m_val - f_img[fidx];
                 mse_score += diff * diff;
-                ssd->num_vox ++;
+                ssd->curr_num_vox ++;
 
             } /* LOOP_THRU_ROI_X */
         } /* LOOP_THRU_ROI_Y */
@@ -2747,8 +2537,8 @@ bspline_score_d_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist_score_omp (mi_hist, ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute Gradient (Parallel across tiles) */
 #pragma omp parallel for
@@ -2857,7 +2647,7 @@ bspline_score_d_mi (
     }
 #endif
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
     if (parms->debug) {
         printf ("<< MSE %3.3f >>\n", mse_score);
     }
@@ -2873,13 +2663,13 @@ bspline_score_c_mi (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume* fixed_roi  = parms->fixed_roi;
-    Volume* moving_roi = parms->moving_roi;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *fixed_roi  = bst->fixed_roi;
+    Volume *moving_roi = bst->moving_roi;
 
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     //plm_long rijk[3];
     plm_long fijk[3], fidx;
     float mijk[3];
@@ -2985,7 +2775,7 @@ bspline_score_c_mi (
                 /* Compute intensity difference */
                 diff = m_val - f_img[fidx];
                 mse_score += diff * diff;
-                ssd->num_vox++;
+                ssd->curr_num_vox++;
 
             } /* LOOP_THRU_ROI_X */
         } /* LOOP_THRU_ROI_Y */
@@ -3019,8 +2809,8 @@ bspline_score_c_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist->compute_score (ssd->num_vox);
-    num_vox_f = (float) ssd->num_vox;
+    ssd->curr_smetric = mi_hist->compute_score (ssd->curr_num_vox);
+    num_vox_f = (float) ssd->curr_num_vox;
 
     /* PASS 2 - Compute gradient */
     LOOP_Z (fijk, fxyz, fixed) {
@@ -3095,7 +2885,7 @@ bspline_score_c_mi (
     }
 #endif
 
-    mse_score = mse_score / ssd->num_vox;
+    mse_score = mse_score / ssd->curr_num_vox;
 }
 
 /* Mutual information version of implementation "k" */
@@ -3107,7 +2897,7 @@ bspline_score_k_mi (
     Bspline_parms *parms = bod->get_bspline_parms ();
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
 
     double* f_hist = mi_hist->f_hist;
     double* m_hist = mi_hist->m_hist;
@@ -3150,7 +2940,7 @@ bspline_score_k_mi (
     }
 
     /* Compute score */
-    ssd->smetric[0] = mi_hist->compute_score (ssd->num_vox);
+    ssd->curr_smetric = mi_hist->compute_score (ssd->curr_num_vox);
 
     /* Create/initialize bspline_loop_user (PASS 2) */
     Bspline_mi_k_pass_2 blu2 (bod);
@@ -3169,7 +2959,7 @@ bspline_score_l_mi (
     Bspline_parms *parms = bod->get_bspline_parms ();
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_score* ssd = &bst->ssd;
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
 
     double* f_hist = mi_hist->f_hist;
     double* m_hist = mi_hist->m_hist;
@@ -3212,7 +3002,7 @@ bspline_score_l_mi (
     }
 
     /* Compute score */
-    ssd->smetric[bst->sm] = mi_hist->compute_score (ssd->num_vox);
+    ssd->curr_smetric = mi_hist->compute_score (ssd->curr_num_vox);
 
     /* Create/initialize bspline_loop_user (PASS 2) */
     Bspline_mi_k_pass_2 blu2 (bod);
@@ -3228,9 +3018,10 @@ bspline_score_mi (
 )
 {
     Bspline_parms *parms = bod->get_bspline_parms ();
+    Bspline_state *bst = bod->get_bspline_state ();
 
-    Volume* fixed_roi  = parms->fixed_roi;
-    Volume* moving_roi = parms->moving_roi;
+    Volume* fixed_roi  = bst->fixed_roi;
+    Volume* moving_roi = bst->moving_roi;
     bool have_roi = fixed_roi || moving_roi;
     bool have_histogram_minmax_val = 
         (parms->mi_fixed_image_minVal!=0)
diff --git a/src/plastimatch/register/bspline_mi.h b/src/plastimatch/register/bspline_mi.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/register/bspline_mi.txx b/src/plastimatch/register/bspline_mi.txx
index b0f4d58..3f64ed1 100755
--- a/src/plastimatch/register/bspline_mi.txx
+++ b/src/plastimatch/register/bspline_mi.txx
@@ -9,7 +9,7 @@
 static inline void
 bspline_mi_pvi_8_dc_dv_dcos (
     float dc_dv[3],                /* Output */
-    Bspline_mi_hist_set* mi_hist,  /* Input */
+    Joint_histogram* mi_hist,  /* Input */
     Bspline_state *bst,            /* Input */
     const Volume *fixed,           /* Input */
     const Volume *moving,          /* Input */
@@ -94,7 +94,7 @@ bspline_mi_pvi_8_dc_dv_dcos (
         }
         idx_jbin = offset_fbin + idx_mbin;
         if (j_hist[idx_jbin] > 0.0001) {
-            dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->smetric[0];
+            dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
             dc_dv[0] -= dw[3*idx_pv+0] * dS_dP;
             dc_dv[1] -= dw[3*idx_pv+1] * dS_dP;
             dc_dv[2] -= dw[3*idx_pv+2] * dS_dP;
@@ -123,12 +123,12 @@ class Bspline_mi_k_pass_1
 {
 public:
     double score_acc;
-    Bspline_mi_hist_set *mi_hist;
+    Joint_histogram *mi_hist;
 public:
     Bspline_mi_k_pass_1 (Bspline_optimize *bod) {
         score_acc = 0.f;
     }
-    void set_mi_hist (Bspline_mi_hist_set *mi_hist) {
+    void set_mi_hist (Joint_histogram *mi_hist) {
         this->mi_hist = mi_hist;
     }
 public:
@@ -168,7 +168,7 @@ public:
         );
 
         /* Keep track of voxels used */
-        ssd->num_vox++;
+        ssd->curr_num_vox++;
     }
 };
 
@@ -176,13 +176,13 @@ class Bspline_mi_k_pass_2
 {
 public:
     float num_vox_f;
-    Bspline_mi_hist_set *mi_hist;
+    Joint_histogram *mi_hist;
 public:
     Bspline_mi_k_pass_2 (Bspline_optimize *bod) {
         Bspline_score* ssd = bod->get_bspline_state()->get_bspline_score();
-        num_vox_f = (float) ssd->num_vox;
+        num_vox_f = (float) ssd->curr_num_vox;
     }
-    void set_mi_hist (Bspline_mi_hist_set *mi_hist) {
+    void set_mi_hist (Joint_histogram *mi_hist) {
         this->mi_hist = mi_hist;
     }
 public:
diff --git a/src/plastimatch/register/bspline_mi_hist.h b/src/plastimatch/register/bspline_mi_hist.h
deleted file mode 100755
index 2f0e833..0000000
--- a/src/plastimatch/register/bspline_mi_hist.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -----------------------------------------------------------------------
-   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
-   ----------------------------------------------------------------------- */
-#ifndef _bspline_mi_hist_h_
-#define _bspline_mi_hist_h_
-
-#include "plmregister_config.h"
-#include <string>
-#include "plm_int.h"
-
-/* Maximum # of bins for a vopt histogram */
-#define VOPT_RES 1000
-
-class Volume;
-
-/* -----------------------------------------------------------------------
-   Types
-   ----------------------------------------------------------------------- */
-enum Mi_hist_type {
-    HIST_EQSP,
-    HIST_VOPT
-};
-
-class PLMREGISTER_API Bspline_mi_hist {
-public:
-    Bspline_mi_hist (
-        Mi_hist_type type = HIST_EQSP, 
-        plm_long bins = 32);
-    ~Bspline_mi_hist ();
-public:
-    /* Used by all histogram types */
-    enum Mi_hist_type type;   /* Type of histograms */
-    plm_long bins;                    /* # of bins in histogram  */
-    float offset;                     /* minimum voxel intensity */
-    plm_long big_bin;                 /* fullest bin index       */
-    float delta;                      /* bin OR key spacing   */
-
-    /* For V-Optimal Histograms */
-    plm_long keys;                    /* # of keys               */
-    int* key_lut;                     /* bin keys lookup table   */
-};
-
-class PLMREGISTER_API Bspline_mi_hist_set {
-public:
-    Bspline_mi_hist_set ();
-    Bspline_mi_hist_set (
-        Mi_hist_type type,
-        plm_long fixed_bins,
-        plm_long moving_bins);
-    ~Bspline_mi_hist_set ();
-public:
-    void initialize (Volume *fixed, Volume *moving);
-    void reset_histograms ();
-    void dump_hist (int it, const std::string& prefix);
-
-    void add_pvi_8 (
-        const Volume *fixed, 
-        const Volume *moving, 
-        int fidx, 
-        int mvf, 
-        float li_1[3],      /* Fraction of interpolant in lower index */
-        float li_2[3]);     /* Fraction of interpolant in upper index */
-
-    float compute_score (int num_vox);
-
-public:
-    Bspline_mi_hist moving;
-    Bspline_mi_hist fixed;
-    Bspline_mi_hist joint;    // JAS: for big_bin
-    double* m_hist;
-    double* f_hist;
-    double* j_hist;
-protected:
-    void allocate ();
-};
-
-#endif
diff --git a/src/plastimatch/register/bspline_mse.cxx b/src/plastimatch/register/bspline_mse.cxx
index b976b2d..210dbb8 100644
--- a/src/plastimatch/register/bspline_mse.cxx
+++ b/src/plastimatch/register/bspline_mse.cxx
@@ -55,15 +55,16 @@ bspline_score_normalize (
        to exit prematurely.  
        However, the best score is not currently stored in the state.  
     */
-    if (ssd->num_vox < MIN_VOX) {
-        ssd->smetric[bst->sm] = FLT_MAX;
+    if (ssd->curr_num_vox < MIN_VOX) {
+        ssd->curr_smetric = FLT_MAX;
         for (int i = 0; i < bxf->num_coeff; i++) {
-            ssd->smetric_grad[i] = 0;
+            ssd->curr_smetric_grad[i] = 0;
         }
     } else {
-        ssd->smetric[bst->sm] = raw_score / ssd->num_vox;
+        ssd->curr_smetric = raw_score / ssd->curr_num_vox;
         for (int i = 0; i < bxf->num_coeff; i++) {
-            ssd->smetric_grad[i] = 2 * ssd->smetric_grad[i] / ssd->num_vox;
+            ssd->curr_smetric_grad[i] 
+                = 2 * ssd->curr_smetric_grad[i] / ssd->curr_num_vox;
         }
     }
 }
@@ -84,9 +85,9 @@ bspline_score_i_mse (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
     Bspline_score* ssd = &bst->ssd;
     double score_tile;
@@ -102,8 +103,8 @@ bspline_score_i_mse (
     float* cond_y = (float*)malloc(cond_size);
     float* cond_z = (float*)malloc(cond_size);
 
-    Volume* fixed_roi  = parms->fixed_roi;
-    Volume* moving_roi = parms->moving_roi;
+    Volume* fixed_roi  = bst->fixed_roi;
+    Volume* moving_roi = bst->moving_roi;
 
     static int it = 0;
 
@@ -270,7 +271,7 @@ bspline_score_i_mse (
 
     } /* LOOP_THRU_VOL_TILES */
 
-    ssd->num_vox = num_vox;
+    ssd->curr_num_vox = num_vox;
 
     /* Now we have a ton of bins and each bin's 64 slots are full.
      * Let's sum each bin's 64 slots.  The result with be dc_dp. */
@@ -311,9 +312,9 @@ bspline_score_h_mse (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
     Bspline_score* ssd = &bst->ssd;
     double score_tile;
@@ -456,7 +457,7 @@ bspline_score_h_mse (
 
                     // Store the score!
                     score_tile += diff * diff;
-                    ssd->num_vox++;
+                    ssd->curr_num_vox++;
 
                     // Compute dc_dv
                     dc_dv[0] = diff * m_grad[3 * idx_moving_round + 0];
@@ -527,9 +528,9 @@ bspline_score_g_mse (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
     Bspline_score* ssd = &bst->ssd;
     double score_tile;
@@ -706,7 +707,7 @@ bspline_score_g_mse (
 
     } /* LOOP_THRU_VOL_TILES */
 
-    ssd->num_vox = num_vox;
+    ssd->curr_num_vox = num_vox;
 
     /* Now we have a ton of bins and each bin's 64 slots are full.
      * Let's sum each bin's 64 slots.  The result with be dc_dp. */
@@ -739,9 +740,9 @@ bspline_score_c_mse (
     Bspline_state *bst = bod->get_bspline_state ();
     Bspline_xform *bxf = bod->get_bspline_xform ();
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
     Bspline_score* ssd = &bst->ssd;
     plm_long fijk[3], fv;         /* Indices within fixed image (vox) */
@@ -874,7 +875,7 @@ bspline_score_c_mse (
                 }
 
                 score_acc += diff * diff;
-                ssd->num_vox++;
+                ssd->curr_num_vox++;
 
             } /* LOOP_THRU_ROI_X */
         } /* LOOP_THRU_ROI_Y */
@@ -949,13 +950,9 @@ bspline_score_mse (
 {
     Bspline_parms *parms = bod->get_bspline_parms ();
     Bspline_state *bst = bod->get_bspline_state ();
-    Bspline_xform *bxf = bod->get_bspline_xform ();
-
-    Regularization_parms* reg_parms = parms->reg_parms;
-    Bspline_landmarks* blm = parms->blm;
 
-    Volume* fixed_roi  = parms->fixed_roi;
-    Volume* moving_roi = parms->moving_roi;
+    Volume* fixed_roi  = bst->fixed_roi;
+    Volume* moving_roi = bst->moving_roi;
     bool have_roi = fixed_roi || moving_roi;
 
     /* CPU Implementations */
diff --git a/src/plastimatch/register/bspline_mse.h b/src/plastimatch/register/bspline_mse.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/register/bspline_mse.txx b/src/plastimatch/register/bspline_mse.txx
index 1a01c13..727981b 100755
--- a/src/plastimatch/register/bspline_mse.txx
+++ b/src/plastimatch/register/bspline_mse.txx
@@ -15,8 +15,8 @@ public:
 public:
     Bspline_mse_k (Bspline_optimize *bod)
     {
-        Bspline_parms *parms = bod->get_bspline_parms ();
-        Volume *moving_grad = parms->moving_grad;
+        Bspline_state *bst = bod->get_bspline_state ();
+        Volume *moving_grad = bst->moving_grad;
         m_grad = (float*) moving_grad->img;
         score_acc = 0.;
     }
@@ -64,7 +64,7 @@ public:
         this->score_acc += diff * diff;
 
         /* Update voxel count */
-        ssd->num_vox++;
+        ssd->curr_num_vox++;
 
         /* Compute spatial gradient using nearest neighbors */
         dc_dv[0] = diff * m_grad[3*mvr+0];  /* x component */
@@ -73,7 +73,6 @@ public:
 
         /* Update cost function gradient */
         ssd->update_smetric_grad_b (bxf, pidx, qidx, dc_dv);
-        ssd->num_vox++;
     }
 };
 
@@ -97,8 +96,8 @@ public:
 public:
     Bspline_mse_l (Bspline_optimize *bod)
     {
-        Bspline_parms *parms = bod->get_bspline_parms ();
-        Volume *moving_grad = parms->moving_grad;
+        Bspline_state *bst = bod->get_bspline_state ();
+        Volume *moving_grad = bst->moving_grad;
         m_grad = (float*) moving_grad->img;
         score_acc = 0.;
     }
@@ -148,7 +147,7 @@ public:
         this->score_acc += diff * diff;
 
         /* Update voxel count */
-        ssd->num_vox++;
+        ssd->curr_num_vox++;
 
         /* Compute spatial gradient using nearest neighbors */
         dc_dv[0] = diff * m_grad[3*mvr+0];  /* x component */
diff --git a/src/plastimatch/register/bspline_optimize.cxx b/src/plastimatch/register/bspline_optimize.cxx
index ddff731..4b6ee64 100644
--- a/src/plastimatch/register/bspline_optimize.cxx
+++ b/src/plastimatch/register/bspline_optimize.cxx
@@ -32,10 +32,7 @@ public:
 Bspline_optimize::Bspline_optimize ()
 {
     d_ptr = new Bspline_optimize_private;
-
-    fixed = 0;
-    moving = 0;
-    moving_grad = 0;
+    d_ptr->bst = Bspline_state::New ();
 }
 
 Bspline_optimize::~Bspline_optimize ()
@@ -43,37 +40,6 @@ Bspline_optimize::~Bspline_optimize ()
     delete d_ptr;
 }
 
-void 
-Bspline_optimize::initialize (Bspline_xform *bxf, Bspline_parms *parms)
-{
-    d_ptr->parms = parms;
-    d_ptr->bst = Bspline_state::New ();
-    d_ptr->bxf = bxf;
-
-    d_ptr->bst->initialize (bxf, parms);
-}
-
-static void
-log_parms (Bspline_parms* parms)
-{
-    logfile_printf ("BSPLINE PARMS\n");
-    logfile_printf ("max_its = %d\n", parms->max_its);
-    logfile_printf ("max_feval = %d\n", parms->max_feval);
-}
-
-static void
-log_bxf_header (Bspline_xform* bxf)
-{
-    logfile_printf ("BSPLINE XFORM HEADER\n");
-    logfile_printf ("vox_per_rgn = %d %d %d\n", 
-        bxf->vox_per_rgn[0], bxf->vox_per_rgn[1], bxf->vox_per_rgn[2]);
-    logfile_printf ("roi_offset = %d %d %d\n", 
-        bxf->roi_offset[0], bxf->roi_offset[1], bxf->roi_offset[2]);
-    logfile_printf ("roi_dim = %d %d %d\n", 
-        bxf->roi_dim[0], bxf->roi_dim[1], bxf->roi_dim[2]);
-    logfile_printf ("img_dc = %s\n", bxf->dc.get_string().c_str());
-}
-
 static void
 bspline_optimize_select (
     Bspline_optimize *bod
@@ -119,26 +85,36 @@ bspline_optimize_select (
 }
 
 void
-bspline_optimize (
-    Bspline_xform *bxf, 
-    Bspline_parms *parms
+Bspline_optimize::optimize (
 )
 {
-    Bspline_optimize bod;
-    bod.initialize (bxf, parms);
+    Bspline_parms *parms = this->get_bspline_parms ();
+    Bspline_state *bst = this->get_bspline_state ();
+    Bspline_xform *bxf = this->get_bspline_xform ();
+    
+    d_ptr->bst->initialize (bxf, parms);
+
+    /* GCS FIX: The below does not belong in bspline_state.  And it should 
+       be done if any similarity metric is MI. */
+    /* JAS Fix 2011.09.14
+     *   The MI algorithm will get stuck for a set of coefficients all equaling
+     *   zero due to the method we use to compute the cost function gradient.
+     *   However, it is possible we could be inheriting coefficients from a
+     *   prior stage, so we must check for inherited coefficients before
+     *   applying an initial offset to the coefficient array. */
+    if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) {
+        bxf->jitter_if_zero ();
+    }
 
-    log_parms (parms);
-    log_bxf_header (bxf);
+    parms->log ();
+    bxf->log_header ();
+    bst->log_metric ();
 
-    /* GCS FIX -- this should move into Bspline_state() constructor */
     /* Initialize histograms */
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
-        bod.get_bspline_state()->mi_hist->initialize (
-            parms->fixed, parms->moving);
-    }
+    bst->initialize_mi_histograms ();
 
     /* Do the optimization */
-    bspline_optimize_select (&bod);
+    bspline_optimize_select (this);
 }
 
 Bspline_parms* 
@@ -158,3 +134,15 @@ Bspline_optimize::get_bspline_xform ()
 {
     return d_ptr->bxf;
 }
+
+void 
+Bspline_optimize::set_bspline_parms (Bspline_parms *parms)
+{
+    d_ptr->parms = parms;
+}
+
+void 
+Bspline_optimize::set_bspline_xform (Bspline_xform *bxf)
+{
+    d_ptr->bxf = bxf;
+}
diff --git a/src/plastimatch/register/bspline_optimize.h b/src/plastimatch/register/bspline_optimize.h
index a037c2b..f71147f 100644
--- a/src/plastimatch/register/bspline_optimize.h
+++ b/src/plastimatch/register/bspline_optimize.h
@@ -20,16 +20,12 @@ public:
     Bspline_optimize ();
     ~Bspline_optimize ();
 public:
-    Volume *fixed;
-    Volume *moving;
-    Volume *moving_grad;
-public:
-    void initialize (Bspline_xform *bxf, Bspline_parms *parms);
-
-    /* Get raw objects, needed by CUDA code */
     Bspline_parms* get_bspline_parms ();
     Bspline_state* get_bspline_state ();
     Bspline_xform* get_bspline_xform ();
+    void set_bspline_parms (Bspline_parms *parms);
+    void set_bspline_xform (Bspline_xform *bxf);
+    void optimize ();
 };
 
 PLMREGISTER_C_API void bspline_optimize (
diff --git a/src/plastimatch/register/bspline_optimize_lbfgsb.cxx b/src/plastimatch/register/bspline_optimize_lbfgsb.cxx
index c48753f..cb64c96 100644
--- a/src/plastimatch/register/bspline_optimize_lbfgsb.cxx
+++ b/src/plastimatch/register/bspline_optimize_lbfgsb.cxx
@@ -140,8 +140,6 @@ Nocedal_optimizer::Nocedal_optimizer (Bspline_optimize *bod)
     /* If iprint is 1, the file iterate.dat will be created */
     iprint = 0;
 
-    //factr = 1.0e+7;
-    //pgtol = 1.0e-5;
     factr = parms->lbfgsb_factr;
     pgtol = parms->lbfgsb_pgtol;
 
@@ -220,8 +218,8 @@ bspline_optimize_lbfgsb (
             bspline_score (bod);
 
             /* Save coeff if best score */
-            if (ssd->score < best_score) {
-                best_score = ssd->score;
+            if (ssd->total_score < best_score) {
+                best_score = ssd->total_score;
                 for (int i = 0; i < bxf->num_coeff; i++) {
                     best_coeff[i] = bxf->coeff[i];
                 }
@@ -235,11 +233,11 @@ bspline_optimize_lbfgsb (
             /* Save some debugging information */
             bspline_save_debug_state (parms, bst, bxf);
             if (parms->debug) {
-                fprintf (fp, "%f\n", ssd->score);
+                fprintf (fp, "%f\n", ssd->total_score);
             }
 
             /* Copy from C to fortran (float -> double) */
-            optimizer.f = ssd->score;
+            optimizer.f = ssd->total_score;
             for (int i = 0; i < bxf->num_coeff; i++) {
                 optimizer.g[i] = ssd->total_grad[i];
             }
@@ -253,14 +251,14 @@ bspline_optimize_lbfgsb (
 
             /* Check convergence tolerance */
             if (old_best_score != DBL_MAX) {
-                double score_diff = old_best_score - ssd->score;
+                double score_diff = old_best_score - ssd->total_score;
                 if (score_diff < parms->convergence_tol 
                     && bst->it >= parms->min_its)
                 {
                     break;
                 }
             }
-            old_best_score = ssd->score;
+            old_best_score = ssd->total_score;
 
             /* Update line search start location */
             printf ("Update lss_coeff\n");
diff --git a/src/plastimatch/register/bspline_optimize_liblbfgs.cxx b/src/plastimatch/register/bspline_optimize_liblbfgs.cxx
index ae543f2..c6c6e5a 100644
--- a/src/plastimatch/register/bspline_optimize_liblbfgs.cxx
+++ b/src/plastimatch/register/bspline_optimize_liblbfgs.cxx
@@ -47,7 +47,7 @@ evaluate (
     bst->feval ++;
 
     /* Return cost */
-    return (lbfgsfloatval_t) bst->ssd.score;
+    return (lbfgsfloatval_t) bst->ssd.total_score;
 }
 
 static int
diff --git a/src/plastimatch/register/bspline_optimize_nlopt.cxx b/src/plastimatch/register/bspline_optimize_nlopt.cxx
index a4e719e..e029740 100644
--- a/src/plastimatch/register/bspline_optimize_nlopt.cxx
+++ b/src/plastimatch/register/bspline_optimize_nlopt.cxx
@@ -46,7 +46,7 @@ bspline_optimize_nlopt_score (
     }
 
     /* Return cost */
-    return (double) bst->ssd.score;
+    return (double) bst->ssd.total_score;
 }
 
 void
diff --git a/src/plastimatch/register/bspline_optimize_steepest.cxx b/src/plastimatch/register/bspline_optimize_steepest.cxx
index 1bfd11a..7ecc89f 100644
--- a/src/plastimatch/register/bspline_optimize_steepest.cxx
+++ b/src/plastimatch/register/bspline_optimize_steepest.cxx
@@ -12,7 +12,6 @@
 #endif
 
 #include "bspline.h"
-#include "bspline_cuda.h"
 #include "bspline_optimize.h"
 #include "bspline_optimize_steepest.h"
 #include "bspline_parms.h"
@@ -53,9 +52,10 @@ bspline_optimize_steepest_trace (
         fp = fopen("scores.txt", "w");
     }
 
+    // GCS FIX: I'm pretty sure the below makes no sense.
     // JAS 04.19.2010
     // For Testing...
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
+    if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) {
         alpha = 1.0f;
         printf ("Using alpha_0 (%f)\n", alpha);
     }
@@ -73,7 +73,7 @@ bspline_optimize_steepest_trace (
 
     /* Get score and gradient */
     bspline_score (bod);
-    old_score = bst->ssd.score;
+    old_score = bst->ssd.total_score;
 
     /* Get search direction */
     ssd_grad_norm = 0;
@@ -92,7 +92,7 @@ bspline_optimize_steepest_trace (
     /* Save some debugging information */
     bspline_save_debug_state (parms, bst, bxf);
     if (parms->debug) {
-        fprintf (fp, "%f\n", ssd->score);
+        fprintf (fp, "%f\n", ssd->total_score);
     }
 
     while (bst->it < parms->max_its && bst->feval < parms->max_feval) {
@@ -111,7 +111,7 @@ bspline_optimize_steepest_trace (
         bspline_score (bod);
 
         /* Compute gain ratio with linear model */
-        gr = (old_score - bst->ssd.score) / htg;
+        gr = (old_score - bst->ssd.total_score) / htg;
         if (gr < 0) {
             /* Cost increased.  Keep search direction and reduce trust rgn. */
             alpha = 0.5 * alpha;
@@ -133,7 +133,7 @@ bspline_optimize_steepest_trace (
         /* Save some debugging information */
         bspline_save_debug_state (parms, bst, bxf);
         if (parms->debug) {
-            fprintf (fp, "%f\n", ssd->score);
+            fprintf (fp, "%f\n", ssd->total_score);
         }
 
         /* If score was reduced, we accept the line search (fall through). 
@@ -151,7 +151,7 @@ bspline_optimize_steepest_trace (
         success ++;
         memcpy (x, bxf->coeff, bxf->num_coeff * sizeof(float));
         memcpy (grad_backup, ssd->total_grad, bxf->num_coeff * sizeof(float));
-        score_backup = ssd->score;
+        score_backup = ssd->total_score;
         sprintf (filename, "grad_%04i.csv", success);
         trace = fopen(filename, "w");
         printf ("Capturing Gradient (grad_%04i.csv)\n", success);
@@ -167,14 +167,14 @@ bspline_optimize_steepest_trace (
             printf ("\t");
             bspline_score (bod);
         
-            fprintf (trace, "%d, %10.10f\n", i, bst->ssd.score);
+            fprintf (trace, "%d, %10.10f\n", i, bst->ssd.total_score);
             fflush(trace);
         }
         fclose (trace);
 
         printf ("Finished Capturing Gradient.\n\n");
         memcpy (ssd->total_grad, grad_backup, bxf->num_coeff * sizeof(float));
-        ssd->score = score_backup;
+        ssd->total_score = score_backup;
 
         /* Start new line search */
         ssd_grad_norm = 0;
@@ -187,12 +187,12 @@ bspline_optimize_steepest_trace (
             h[i] = - ssd->total_grad[i] / ssd_grad_norm;
             htg -= h[i] * ssd->total_grad[i];
         }
-        old_score = bst->ssd.score;
+        old_score = bst->ssd.total_score;
     }
 
     /* Save best result */
     memcpy (bxf->coeff, x, bxf->num_coeff * sizeof(float));
-    bst->ssd.score = old_score;
+    bst->ssd.total_score = old_score;
 
     if (parms->debug) {
         fclose (fp);
@@ -234,9 +234,10 @@ bspline_optimize_steepest_trust (
         fp = fopen("scores.txt", "w");
     }
 
+    // GCS FIX: I'm pretty sure the below makes no sense.
     // JAS 04.19.2010
     // For testing...
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
+    if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) {
         alpha = 1.0f;
         printf ("Using alpha_0 (%f)\n", alpha);
     }
@@ -252,7 +253,7 @@ bspline_optimize_steepest_trust (
 
     /* Get score and gradient */
     bspline_score (bod);
-    old_score = bst->ssd.score;
+    old_score = bst->ssd.total_score;
 
     /* Get search direction */
     ssd_grad_norm = 0;
@@ -272,7 +273,7 @@ bspline_optimize_steepest_trust (
     /* Save some debugging information */
     bspline_save_debug_state (parms, bst, bxf);
     if (parms->debug) {
-        fprintf (fp, "%f\n", ssd->score);
+        fprintf (fp, "%f\n", ssd->total_score);
     }
 
     while (bst->it < parms->max_its && bst->feval < parms->max_feval) {
@@ -291,7 +292,7 @@ bspline_optimize_steepest_trust (
         bspline_score (bod);
 
         /* Compute gain ratio with linear model */
-        gr = (old_score - bst->ssd.score) / htg;
+        gr = (old_score - bst->ssd.total_score) / htg;
         if (gr < 0) {
             /* Cost increased.  Keep search direction and reduce trust rgn. */
             alpha = 0.5 * alpha;
@@ -313,7 +314,7 @@ bspline_optimize_steepest_trust (
         /* Save some debugging information */
         bspline_save_debug_state (parms, bst, bxf);
         if (parms->debug) {
-            fprintf (fp, "%f\n", ssd->score);
+            fprintf (fp, "%f\n", ssd->total_score);
         }
 
         /* If score was reduced, we accept the line search */
@@ -334,12 +335,12 @@ bspline_optimize_steepest_trust (
             h[i] = - ssd->total_grad[i] / ssd_grad_norm;
             htg -= h[i] * ssd->total_grad[i];
         }
-        old_score = bst->ssd.score;
+        old_score = bst->ssd.total_score;
     }
 
     /* Save best result */
     memcpy (bxf->coeff, x, bxf->num_coeff * sizeof(float));
-    bst->ssd.score = old_score;
+    bst->ssd.total_score = old_score;
 
     if (parms->debug) {
         fclose (fp);
@@ -379,7 +380,7 @@ bspline_optimize_steepest_naive (
 
     /* Get score and gradient */
     bspline_score (bod);
-    old_score = bst->ssd.score;
+    old_score = bst->ssd.total_score;
 
     /* Set alpha based on norm gradient */
     ssd_grad_norm = 0;
@@ -395,7 +396,7 @@ bspline_optimize_steepest_naive (
     /* Save some debugging information */
     bspline_save_debug_state (parms, bst, bxf);
     if (parms->debug) {
-        fprintf (fp, "%f\n", ssd->score);
+        fprintf (fp, "%f\n", ssd->total_score);
     }
 
     while (bst->it < parms->max_its && bst->feval < parms->max_feval) {
@@ -416,19 +417,19 @@ bspline_optimize_steepest_naive (
         bspline_score (bod);
 
         /* Update gamma */
-        if (bst->ssd.score < old_score) {
+        if (bst->ssd.total_score < old_score) {
             gamma *= gain;
         } else {
             gamma /= gain;
         }
-        old_score = bst->ssd.score;
+        old_score = bst->ssd.total_score;
 
         /* Give a little feedback to the user */
         bspline_display_coeff_stats (bxf);
         /* Save some debugging information */
         bspline_save_debug_state (parms, bst, bxf);
         if (parms->debug) {
-            fprintf (fp, "%f\n", ssd->score);
+            fprintf (fp, "%f\n", ssd->total_score);
         }
     }
 
diff --git a/src/plastimatch/register/bspline_parms.cxx b/src/plastimatch/register/bspline_parms.cxx
index 46cf12b..bf4b1ad 100644
--- a/src/plastimatch/register/bspline_parms.cxx
+++ b/src/plastimatch/register/bspline_parms.cxx
@@ -6,14 +6,12 @@
 #include "bspline_parms.h"
 #include "bspline_landmarks.h"
 #include "bspline_regularize.h"
+#include "logfile.h"
 
 Bspline_parms::Bspline_parms ()
 {
     this->threading = BTHR_CPU;
     this->optimization = BOPT_LBFGSB;
-    this->metric_type.push_back (REGISTRATION_METRIC_MSE);
-    this->metric_lambda.push_back (1.0);
-    this->implementation = '\0';
     this->min_its = 0;
     this->max_its = 10;
     this->max_feval = 10;
@@ -36,12 +34,6 @@ Bspline_parms::Bspline_parms ()
     this->lbfgsb_pgtol = 1.0e-5;
     this->lbfgsb_mmax = -1;
 
-    this->fixed = 0;
-    this->moving = 0;
-    this->fixed_grad = 0;
-    this->moving_grad = 0;
-    this->fixed_roi = 0;
-    this->moving_roi = 0;
     this->fixed_stiffness = 0;
 
     this->reg_parms = new Regularization_parms;
@@ -57,3 +49,11 @@ Bspline_parms::~Bspline_parms ()
     delete this->blm;
     delete this->reg_parms;
 }
+
+void
+Bspline_parms::log ()
+{
+    logfile_printf ("BSPLINE PARMS\n");
+    logfile_printf ("max_its = %d\n", this->max_its);
+    logfile_printf ("max_feval = %d\n", this->max_feval);
+}
diff --git a/src/plastimatch/register/bspline_parms.h b/src/plastimatch/register/bspline_parms.h
index 6fee4be..0a98378 100644
--- a/src/plastimatch/register/bspline_parms.h
+++ b/src/plastimatch/register/bspline_parms.h
@@ -5,11 +5,13 @@
 #define _bspline_parms_h_
 
 #include "plmregister_config.h"
+#include <list>
 #include <string>
 #include <vector>
-#include "bspline_mi_hist.h"
 #include "double_align8.h"
-#include "registration_metric_type.h"
+#include "joint_histogram.h"
+#include "metric_state.h"
+#include "similarity_metric_type.h"
 #include "smart_pointer.h"
 
 enum BsplineOptimization {
@@ -37,52 +39,56 @@ public:
     Bspline_parms ();
     ~Bspline_parms ();
 public:
-    enum BsplineThreading threading;
+    /* General optimizer parms */
     enum BsplineOptimization optimization;
-    std::vector<Registration_metric_type> metric_type;
-    std::vector<float> metric_lambda;
-    char implementation;         /* Implementation ('a', 'b', etc.) */
     int min_its;                 /* Miniumum iterations (line searches) */
     int max_its;                 /* Max iterations (line searches) */
     int max_feval;               /* Max function evaluations */
+    double_align8 convergence_tol; /* When to stop iterations based on score */
+
+    /* LBFGSB optimizer parms */
+    double_align8 lbfgsb_factr;  /* Function value tolerance for L-BFGS-B */
+    double_align8 lbfgsb_pgtol;  /* Projected grad tolerance for L-BFGS-B */
+    int lbfgsb_mmax;             /* Number of rows in M matrix */
+
+    /* Debugging */
     int debug;                   /* Create grad & histogram files */
     std::string debug_dir;       /* Directory where to create debug files */
     int debug_stage;             /* Used to tag debug files by stage */
+    char* xpm_hist_dump;         /* Pointer to base string of hist dumps */
+
+    /* Threading */
+    enum BsplineThreading threading;
     int gpuid;                   /* Sets GPU to use for multi-gpu machines */
-    double_align8 convergence_tol; /* When to stop iterations based on score */
 
-    /* MI parms */
+    /*! \brief Implementation ('a', 'b', etc.) -- to be moved into 
+      Stage_similarity_data */
+    char implementation;
+
+    /* MI similarity metric */
     enum Mi_hist_type mi_hist_type;
     plm_long mi_hist_fixed_bins;
     plm_long mi_hist_moving_bins;
 
+    /* Image ROI selection */
     float mi_fixed_image_minVal;
     float mi_fixed_image_maxVal;
     float mi_moving_image_minVal;
     float mi_moving_image_maxVal;
 
-    /* LBFGSB optimizer parms */
-    double_align8 lbfgsb_factr;  /* Function value tolerance for L-BFGS-B */
-    double_align8 lbfgsb_pgtol;  /* Projected grad tolerance for L-BFGS-B */
-    int lbfgsb_mmax;             /* Number of rows in M matrix */
-
-    /* Image Volumes - these are not owned by Bspline_parms */
-    Volume* fixed;
-    Volume* moving;
-    Volume* fixed_grad;
-    Volume* moving_grad;
-    Volume* fixed_roi;
-    Volume* moving_roi;
-    Volume* fixed_stiffness;
-
     /* Regularization */
-    Regularization_parms* reg_parms;        /* Regularization Parameters */
+    Regularization_parms* reg_parms;
+    Volume* fixed_stiffness;
 
     /* Landmarks */
     Bspline_landmarks* blm;      /* Landmarks parameters */
-    float rbf_radius;            /* Radius of RBF; if rbf_radius>0, RBF are used */
-    float rbf_young_modulus;     /* Penalty for the large 2nd derivative of RBF vector field */
-    char* xpm_hist_dump;         /* Pointer to base string of hist dumps */
+    /*! \brief Radius of RBF; if rbf_radius>0, RBF are used */
+    float rbf_radius;
+    /*! \brief Penalty for the large 2nd derivative of RBF vector field */
+    float rbf_young_modulus;
+
+public:
+    void log ();
 };
 
 #endif
diff --git a/src/plastimatch/register/bspline_regularize.cxx b/src/plastimatch/register/bspline_regularize.cxx
index fe15ef0..d85dcf2 100644
--- a/src/plastimatch/register/bspline_regularize.cxx
+++ b/src/plastimatch/register/bspline_regularize.cxx
@@ -12,8 +12,6 @@ Bspline_regularize::Bspline_regularize ()
     /* all methods */
     this->reg_parms = 0;
     this->bxf = 0;
-    this->fixed = 0;
-    this->moving = 0;
     this->fixed_stiffness = 0;
 
     /* semi-analytic method */
diff --git a/src/plastimatch/register/bspline_regularize.h b/src/plastimatch/register/bspline_regularize.h
index 2d07ea3..c7eaba9 100644
--- a/src/plastimatch/register/bspline_regularize.h
+++ b/src/plastimatch/register/bspline_regularize.h
@@ -33,8 +33,6 @@ public:
     Regularization_parms *reg_parms;
     Bspline_xform *bxf;
 
-    Volume* fixed;
-    Volume* moving;
     Volume* fixed_stiffness;
 
     /* numeric methods */
diff --git a/src/plastimatch/register/bspline_score.cxx b/src/plastimatch/register/bspline_score.cxx
index 2c18a8d..e1a805b 100644
--- a/src/plastimatch/register/bspline_score.cxx
+++ b/src/plastimatch/register/bspline_score.cxx
@@ -8,21 +8,24 @@
 
 Bspline_score::Bspline_score ()
 {
-    this->score = 0;
+    this->total_score = 0;
+    this->total_grad = 0;
+
     this->lmetric = 0;
     this->rmetric = 0;
 
-    this->num_vox = 0;
     this->num_coeff = 0;
-    this->smetric_grad = 0;
-    this->total_grad = 0;
+
+    this->curr_num_vox = 0;
+    this->curr_smetric = 0;
+    this->curr_smetric_grad = 0;
 
     this->time_rmetric = 0;
 }
 
 Bspline_score::~Bspline_score ()
 {
-    delete[] smetric_grad;
+    delete[] curr_smetric_grad;
     delete[] total_grad;
 }
 
@@ -30,38 +33,42 @@ void
 Bspline_score::set_num_coeff (plm_long num_coeff)
 {
     this->num_coeff = num_coeff;
-    delete[] this->smetric_grad;
+    delete[] this->curr_smetric_grad;
     delete[] this->total_grad;
-    this->smetric_grad = new float[num_coeff];
+    this->curr_smetric_grad = new float[num_coeff];
     this->total_grad = new float[num_coeff];
 }
 
 void
 Bspline_score::reset_smetric_grad ()
 {
-    memset (this->smetric_grad, 0, this->num_coeff * sizeof(float));
+    memset (this->curr_smetric_grad, 0, this->num_coeff * sizeof(float));
 }
 
 void
 Bspline_score::reset_score ()
 {
-    this->score = 0;
+    this->total_score = 0;
+    memset (this->total_grad, 0, this->num_coeff * sizeof(float));
     this->lmetric = 0;
     this->rmetric = 0;
-    this->smetric.clear();
-    this->num_vox = 0;
-    memset (this->smetric_grad, 0, this->num_coeff * sizeof(float));
-    memset (this->total_grad, 0, this->num_coeff * sizeof(float));
-    this->time_smetric.clear();
+    this->metric_record.clear();
+    this->curr_num_vox = 0;
+    this->curr_smetric = 0;
+    memset (this->curr_smetric_grad, 0, this->num_coeff * sizeof(float));
     this->time_rmetric = 0;
 }
 
 void
-Bspline_score::accumulate_grad (float lambda)
+Bspline_score::accumulate (float lambda)
 {
+    this->total_score += lambda * this->curr_smetric;
     for (plm_long i = 0; i < this->num_coeff; i++) {
-        this->total_grad[i] += lambda * this->smetric_grad[i];
+        this->total_grad[i] += lambda * this->curr_smetric_grad[i];
     }
+
+    this->curr_smetric = 0;
+    this->curr_num_vox = 0;
     this->reset_smetric_grad ();
 }
 
@@ -72,7 +79,7 @@ Bspline_score::update_smetric_grad (
     plm_long qidx,
     const float dc_dv[3])
 {
-    this->update_grad (this->smetric_grad, bxf, p, qidx, dc_dv);
+    this->update_grad (this->curr_smetric_grad, bxf, p, qidx, dc_dv);
 }
 
 void
@@ -92,7 +99,7 @@ Bspline_score::update_smetric_grad_b (
     plm_long qidx, 
     const float dc_dv[3])
 {
-    this->update_grad_b (this->smetric_grad, bxf, pidx, qidx, dc_dv);
+    this->update_grad_b (this->curr_smetric_grad, bxf, pidx, qidx, dc_dv);
 }
 
 void
diff --git a/src/plastimatch/register/bspline_score.h b/src/plastimatch/register/bspline_score.h
index b8c8a49..a01abc9 100644
--- a/src/plastimatch/register/bspline_score.h
+++ b/src/plastimatch/register/bspline_score.h
@@ -10,31 +10,55 @@
 
 class Bspline_xform;
 
+class PLMREGISTER_API Metric_score
+{
+public:
+    Metric_score () {
+        score = 0.f;
+        time = 0.f;
+        num_vox = 0;
+    }
+    Metric_score (float score, float time, plm_long num_vox) 
+        : score(score), time(time), num_vox(num_vox) {
+        score = 0.f;
+        time = 0.f;
+        num_vox = 0;
+    }
+public:
+    float score;
+    double time;
+    plm_long num_vox;
+};
+
 class PLMREGISTER_API Bspline_score
 {
 public:
     Bspline_score ();
     ~Bspline_score ();
 public:
-    float score;           /* Total Score (sent to optimizer) */
+    float total_score;     /* Total Score (sent to optimizer) */
+    float* total_grad;     /* Total cost function gradient */
+
     float lmetric;         /* Landmark metric */
     float rmetric;         /* Regularization metric */
-    std::vector<float> smetric;  /* Similarity metric */
 
-    plm_long num_vox;      /* Number of voxel with correspondence */
+    /*! \brief The metric_record keeps track of score statistics 
+      for reporting purposes */
+    std::vector<Metric_score> metric_record;
+
     plm_long num_coeff;    /* Size of gradient vector = num coefficents */
-    float* smetric_grad;   /* Gradient of score for current smetric */
-    float* total_grad;     /* Total cost function gradient wrt coefficients */
 
-    /* Time to compute similarity metric */
-    std::vector<double> time_smetric;
+    float curr_smetric;         /* Current smetric value */
+    float* curr_smetric_grad;   /* Gradient of score for current smetric */
+    plm_long curr_num_vox;      /* Number of voxel with correspondence */
+
     /* Time to compute regularization metric */
     double time_rmetric;
 public:
     void set_num_coeff (plm_long num_coeff);
     void reset_smetric_grad ();
     void reset_score ();
-    void accumulate_grad (float lambda);
+    void accumulate (float lambda);
     void update_smetric_grad (
         const Bspline_xform* bxf, 
         const plm_long p[3],
diff --git a/src/plastimatch/register/bspline_stage.cxx b/src/plastimatch/register/bspline_stage.cxx
index 9fa08e6..3cfa277 100644
--- a/src/plastimatch/register/bspline_stage.cxx
+++ b/src/plastimatch/register/bspline_stage.cxx
@@ -13,6 +13,7 @@
 #include "bspline_regularize.h"
 #include "bspline_parms.h"
 #include "bspline_stage.h"
+#include "bspline_xform.h"
 #include "logfile.h"
 #include "mha_io.h"
 #include "plm_image_header.h"
@@ -33,18 +34,14 @@
 
 class Bspline_stage_private {
 public:
-    Registration_parms *regp;
     Registration_data *regd;
     const Stage_parms *stage;
     Xform *xf_in;
     Xform::Pointer xf_out;
-    Bspline_parms bsp_parms;
 
-    Volume::Pointer fixed_ss;
-    Volume::Pointer moving_ss;
-    Volume::Pointer moving_grad;
-    Volume::Pointer f_roi_ss;
-    Volume::Pointer m_roi_ss;
+    Bspline_parms parms;
+    Bspline_optimize bod;
+
     Volume::Pointer f_stiffness_ss;
 public:
     Bspline_stage_private () {
@@ -53,13 +50,11 @@ public:
 };
 
 Bspline_stage::Bspline_stage (
-    Registration_parms *regp,
     Registration_data *regd,
     const Stage_parms *stage,
     Xform *xf_in)
 {
     d_ptr = new Bspline_stage_private;
-    d_ptr->regp = regp;
     d_ptr->regd = regd;
     d_ptr->stage = stage;
     d_ptr->xf_in = xf_in;
@@ -102,11 +97,8 @@ update_roi (Volume::Pointer& roi, Volume::Pointer& image, float min_val,
 void
 Bspline_stage::run_stage ()
 {
-    Xform *xf_out = d_ptr->xf_out.get();
-    Bspline_parms *bsp_parms = &d_ptr->bsp_parms;
-
     /* Run bspline optimization */
-    bspline_optimize (xf_out->get_gpuit_bsp(), bsp_parms);
+    d_ptr->bod.optimize ();
 }
 
 void
@@ -117,58 +109,54 @@ Bspline_stage::initialize ()
     const Shared_parms *shared = d_ptr->stage->get_shared_parms();
     Xform *xf_in = d_ptr->xf_in;
     Xform *xf_out = d_ptr->xf_out.get();
-    Bspline_parms *bsp_parms = &d_ptr->bsp_parms;
+    Bspline_optimize *bod = &d_ptr->bod;
+    Bspline_parms *parms = &d_ptr->parms;
+    Bspline_state *bst = bod->get_bspline_state ();
 
-    Plm_image_header pih;
+    /* Tell bod what parameters to use */
+    d_ptr->bod.set_bspline_parms (parms);
 
-    logfile_printf ("Converting fixed\n");
-    Volume::Pointer& fixed = regd->fixed_image->get_volume_float ();
-    logfile_printf ("Converting moving\n");
-    Volume::Pointer& moving = regd->moving_image->get_volume_float ();
-    logfile_printf ("Done.\n");
+    /* Set up metric state */
+    populate_similarity_list (bst->similarity_data, regd, stage);
 
-    Volume::Pointer m_roi;
-    Volume::Pointer f_roi;
+    /* Transform input xform to bspline and give to bod */
+    Plm_image_header pih;
+    pih.set (bst->similarity_data.front()->fixed_ss);
+    xform_to_gpuit_bsp (xf_out, xf_in, &pih, stage->grid_spac);
+    Bspline_xform *bxf = xf_out->get_gpuit_bsp();
+    d_ptr->bod.set_bspline_xform (bxf);
 
     /* Set roi's */
-    if (shared->fixed_roi_enable && regd->fixed_roi) {
-        f_roi = regd->fixed_roi->get_volume_uchar();
-    }
-    if (shared->moving_roi_enable && regd->moving_roi) {
-        m_roi = regd->moving_roi->get_volume_uchar();
+    Volume::Pointer m_roi;
+    Volume::Pointer f_roi;
+    if (shared->fixed_roi_enable && regd->get_fixed_roi()) {
+        f_roi = regd->get_fixed_roi()->get_volume_uchar();
     }
-
-    /* Convert images to gpuit format */
-    fixed->convert (PT_FLOAT);              /* Maybe not necessary? */
-    moving->convert (PT_FLOAT);             /* Maybe not necessary? */
-
-    /* Subsample images */
-    d_ptr->fixed_ss = registration_resample_volume (
-        fixed, stage, stage->resample_rate_fixed);
-    d_ptr->moving_ss = registration_resample_volume (
-        moving, stage, stage->resample_rate_moving);
-
-    /* Gradient magnitude uses different fixed and moving images */
-    if (stage->metric_type[0] == REGISTRATION_METRIC_GM) {
-        d_ptr->fixed_ss = volume_gradient_magnitude (d_ptr->fixed_ss);
-        d_ptr->moving_ss = volume_gradient_magnitude (d_ptr->moving_ss);
+    if (shared->moving_roi_enable && regd->get_moving_roi()) {
+        m_roi = regd->get_moving_roi()->get_volume_uchar();
     }
 
     /* Copy parameters from stage_parms to bspline_parms */
-    bsp_parms->mi_fixed_image_minVal = stage->mi_fixed_image_minVal;
-    bsp_parms->mi_fixed_image_maxVal = stage->mi_fixed_image_maxVal;
-    bsp_parms->mi_moving_image_minVal = stage->mi_moving_image_minVal;
-    bsp_parms->mi_moving_image_maxVal = stage->mi_moving_image_maxVal;
-
-    //Check if min/max values for moving image are set (correctly)
-    if ((bsp_parms->mi_moving_image_minVal!=0 
-            || bsp_parms->mi_moving_image_maxVal!=0) 
-        && (bsp_parms->mi_moving_image_minVal < 
-            bsp_parms->mi_moving_image_maxVal))
+    parms->mi_fixed_image_minVal = stage->mi_fixed_image_minVal;
+    parms->mi_fixed_image_maxVal = stage->mi_fixed_image_maxVal;
+    parms->mi_moving_image_minVal = stage->mi_moving_image_minVal;
+    parms->mi_moving_image_maxVal = stage->mi_moving_image_maxVal;
+
+    /* GCS FIX BEGIN */
+    /* BSpline code needs work to support multi-planar imaging 
+       until that is done, this should maintain the old behavior */
+    Volume::Pointer fixed = regd->get_fixed_image()->get_volume_float();
+    Volume::Pointer moving = regd->get_moving_image()->get_volume_float();
+    
+    // Check if min/max values for moving image are set (correctly)
+    if ((parms->mi_moving_image_minVal!=0 
+            || parms->mi_moving_image_maxVal!=0) 
+        && (parms->mi_moving_image_minVal < 
+            parms->mi_moving_image_maxVal))
     {
         bool fill=!m_roi;
 
-        //create new moving roi if not available
+        // create new moving roi if not available
         if (!m_roi)
         {
             m_roi = Volume::New ();
@@ -176,50 +164,47 @@ Bspline_stage::initialize ()
                 moving->direction_cosines, PT_UCHAR);
         }
 
-        //Modify fixed roi according to min and max values for moving image
-        update_roi (m_roi, moving, bsp_parms->mi_moving_image_minVal,
-            bsp_parms->mi_moving_image_maxVal,fill);
+        // Modify fixed roi according to min and max values for moving image
+        update_roi (m_roi, moving, parms->mi_moving_image_minVal,
+            parms->mi_moving_image_maxVal,fill);
     }
 
-    //Check if min/max values for fixed image are set (correctly)
-    if ((bsp_parms->mi_fixed_image_minVal!=0 
-            || bsp_parms->mi_fixed_image_maxVal!=0) 
-        && (bsp_parms->mi_fixed_image_minVal < 
-            bsp_parms->mi_fixed_image_maxVal))
+    // Check if min/max values for fixed image are set (correctly)
+    if ((parms->mi_fixed_image_minVal!=0 
+            || parms->mi_fixed_image_maxVal!=0) 
+        && (parms->mi_fixed_image_minVal < 
+            parms->mi_fixed_image_maxVal))
     {
         bool fill=!f_roi;
 
-        //create new fixed roi if not available
-        if(!f_roi)
+        // create new fixed roi if not available
+        if (!f_roi)
         {
             f_roi = Volume::New ();
             f_roi->create (fixed->dim, fixed->origin, fixed->spacing,
                 fixed->direction_cosines, PT_UCHAR);
         }
 
-        //Modify fixed roi according to min and max values for fixed image
-        update_roi (f_roi, fixed, bsp_parms->mi_fixed_image_minVal,
-            bsp_parms->mi_fixed_image_maxVal, fill);
+        // Modify fixed roi according to min and max values for fixed image
+        update_roi (f_roi, fixed, parms->mi_fixed_image_minVal,
+            parms->mi_fixed_image_maxVal, fill);
     }
 
     /* Subsample rois (if we are using them) */
     if (m_roi) {
-        d_ptr->m_roi_ss = volume_subsample_vox_legacy_nn (
-            m_roi, stage->resample_rate_moving);
+        Volume::Pointer m_roi_ss = 
+            volume_subsample_vox_legacy_nn (
+                m_roi, stage->resample_rate_moving);
+        bst->similarity_data.front()->moving_roi = m_roi_ss;
     }
     if (f_roi) {
-        d_ptr->f_roi_ss = volume_subsample_vox_legacy_nn (
-            f_roi, stage->resample_rate_fixed);
+        Volume::Pointer f_roi_ss = 
+            volume_subsample_vox_legacy_nn (
+                f_roi, stage->resample_rate_fixed);
+        bst->similarity_data.front()->fixed_roi = f_roi_ss;
     }
 
-    logfile_printf ("moving_ss size = %d %d %d\n", 
-        d_ptr->moving_ss->dim[0], 
-        d_ptr->moving_ss->dim[1], 
-        d_ptr->moving_ss->dim[2]);
-    logfile_printf ("fixed_ss size = %d %d %d\n", 
-        d_ptr->fixed_ss->dim[0], 
-        d_ptr->fixed_ss->dim[1], 
-        d_ptr->fixed_ss->dim[2]);
+    /* GCS FIX END */
 
     /* Subsample stiffness */
     if (shared->fixed_stiffness_enable && regd->fixed_stiffness) {
@@ -229,122 +214,98 @@ Bspline_stage::initialize ()
             stiffness, stage, stage->resample_rate_fixed);
     }
 
-    /* Make spatial gradient image */
-    Volume *moving_grad = volume_make_gradient (d_ptr->moving_ss.get());
-    d_ptr->moving_grad = Volume::New (moving_grad);
-
-    /* --- Initialize parms --- */
-
-    /* Images */
-    bsp_parms->fixed = d_ptr->fixed_ss.get();
-    bsp_parms->moving = d_ptr->moving_ss.get();
-    bsp_parms->moving_grad = d_ptr->moving_grad.get();
-    if (f_roi) {
-        bsp_parms->fixed_roi = d_ptr->f_roi_ss.get();
-    }
-    if (m_roi) {
-        bsp_parms->moving_roi = d_ptr->m_roi_ss.get();
-    }
+    /* Stiffness image */
     if (d_ptr->f_stiffness_ss) {
-        bsp_parms->fixed_stiffness = d_ptr->f_stiffness_ss.get();
+        parms->fixed_stiffness = d_ptr->f_stiffness_ss.get();
     }
 
     /* Optimization */
     if (stage->optim_type == OPTIMIZATION_STEEPEST) {
-        bsp_parms->optimization = BOPT_STEEPEST;
+        parms->optimization = BOPT_STEEPEST;
     } else if (stage->optim_type == OPTIMIZATION_LIBLBFGS) {
-        bsp_parms->optimization = BOPT_LIBLBFGS;
+        parms->optimization = BOPT_LIBLBFGS;
     } else {
-        bsp_parms->optimization = BOPT_LBFGSB;
-    }
-    bsp_parms->lbfgsb_pgtol = stage->pgtol;
-    bsp_parms->lbfgsb_mmax = stage->lbfgsb_mmax;
-
-    /* Metric */
-    bsp_parms->metric_type = stage->metric_type;
-    bsp_parms->metric_lambda = stage->metric_lambda;
-    for (size_t i = 0; i < stage->metric_type.size(); i++) {
-        if (bsp_parms->metric_type[i] == REGISTRATION_METRIC_MI_VW) {
-            bsp_parms->metric_type[i] = REGISTRATION_METRIC_MI_MATTES;
-        }
+        parms->optimization = BOPT_LBFGSB;
     }
+    parms->lbfgsb_pgtol = stage->pgtol;
+    parms->lbfgsb_mmax = stage->lbfgsb_mmax;
 
     /* Threading */
     switch (stage->threading_type) {
     case THREADING_CPU_SINGLE:
         if (stage->alg_flavor == 0) {
-            bsp_parms->implementation = 'h';
+            parms->implementation = 'h';
         } else {
-            bsp_parms->implementation = stage->alg_flavor;
+            parms->implementation = stage->alg_flavor;
         }
-        bsp_parms->threading = BTHR_CPU;
+        parms->threading = BTHR_CPU;
         break;
     case THREADING_CPU_OPENMP:
         if (stage->alg_flavor == 0) {
-            bsp_parms->implementation = 'g';
+            parms->implementation = 'g';
         } else {
-            bsp_parms->implementation = stage->alg_flavor;
+            parms->implementation = stage->alg_flavor;
         }
-        bsp_parms->threading = BTHR_CPU;
+        parms->threading = BTHR_CPU;
         break;
     case THREADING_CUDA:
         if (stage->alg_flavor == 0) {
-            bsp_parms->implementation = 'j';
+            parms->implementation = 'j';
         } else {
-            bsp_parms->implementation = stage->alg_flavor;
+            parms->implementation = stage->alg_flavor;
         }
-        bsp_parms->threading = BTHR_CUDA;
+        parms->threading = BTHR_CUDA;
         break;
     default:
         print_and_exit ("Undefined impl type in gpuit_bspline\n");
     }
-    logfile_printf ("Algorithm flavor = %c\n", bsp_parms->implementation);
-    logfile_printf ("Threading = %d\n", bsp_parms->threading);
+    logfile_printf ("Algorithm flavor = %c\n", parms->implementation);
+    logfile_printf ("Threading = %d\n", parms->threading);
 
     if (stage->threading_type == THREADING_CUDA) {
-        bsp_parms->gpuid = stage->gpuid;
-        logfile_printf ("GPU ID = %d\n", bsp_parms->gpuid);
+        parms->gpuid = stage->gpuid;
+        logfile_printf ("GPU ID = %d\n", parms->gpuid);
     }
     
     /* Regularization */
-    bsp_parms->reg_parms->lambda = stage->regularization_lambda;
+    parms->reg_parms->lambda = stage->regularization_lambda;
     switch (stage->regularization_type) {
     case REGULARIZATION_NONE:
-        bsp_parms->reg_parms->lambda = 0.0f;
+        parms->reg_parms->lambda = 0.0f;
         break;
     case REGULARIZATION_BSPLINE_ANALYTIC:
         if (stage->threading_type == THREADING_CPU_OPENMP) {
-            bsp_parms->reg_parms->implementation = 'c';
+            parms->reg_parms->implementation = 'c';
         } else {
-            bsp_parms->reg_parms->implementation = 'b';
+            parms->reg_parms->implementation = 'b';
         }
         break;
     case REGULARIZATION_BSPLINE_SEMI_ANALYTIC:
-        bsp_parms->reg_parms->implementation = 'd';
+        parms->reg_parms->implementation = 'd';
         break;
     case REGULARIZATION_BSPLINE_NUMERIC:
-        bsp_parms->reg_parms->implementation = 'a';
+        parms->reg_parms->implementation = 'a';
         break;
     default:
         print_and_exit ("Undefined regularization type in gpuit_bspline\n");
     }
     if (stage->regularization_lambda != 0) {
-        bsp_parms->reg_parms->lambda = stage->regularization_lambda;
+        parms->reg_parms->lambda = stage->regularization_lambda;
     }
     logfile_printf ("Regularization: flavor = %c lambda = %f\n", 
-        bsp_parms->reg_parms->implementation,
-        bsp_parms->reg_parms->lambda);
+        parms->reg_parms->implementation,
+        parms->reg_parms->lambda);
 
     /* Mutual information histograms */
-    bsp_parms->mi_hist_type = stage->mi_hist_type;
-    bsp_parms->mi_hist_fixed_bins = stage->mi_hist_fixed_bins;
-    bsp_parms->mi_hist_moving_bins = stage->mi_hist_moving_bins;
+    parms->mi_hist_type = stage->mi_hist_type;
+    parms->mi_hist_fixed_bins = stage->mi_hist_fixed_bins;
+    parms->mi_hist_moving_bins = stage->mi_hist_moving_bins;
 
     /* Other stuff */
-    bsp_parms->min_its = stage->min_its;
-    bsp_parms->max_its = stage->max_its;
-    bsp_parms->max_feval = stage->max_its;
-    bsp_parms->convergence_tol = stage->convergence_tol;
+    parms->min_its = stage->min_its;
+    parms->max_its = stage->max_its;
+    parms->max_feval = stage->max_its;
+    parms->convergence_tol = stage->convergence_tol;
 
     /* Landmarks */
     if (regd->fixed_landmarks && regd->moving_landmarks) {
@@ -352,37 +313,34 @@ Bspline_stage::initialize ()
             regd->fixed_landmarks->get_count(),
             regd->moving_landmarks->get_count(),
             stage->landmark_stiffness);
-        bsp_parms->blm->set_landmarks (regd->fixed_landmarks, 
+        parms->blm->set_landmarks (regd->fixed_landmarks, 
             regd->moving_landmarks);
-        bsp_parms->blm->landmark_implementation = stage->landmark_flavor;
-        bsp_parms->blm->landmark_stiffness = stage->landmark_stiffness;
+        parms->blm->landmark_implementation = stage->landmark_flavor;
+        parms->blm->landmark_stiffness = stage->landmark_stiffness;
     }
 
-    /* Transform input xform to gpuit vector field */
-    pih.set_from_gpuit (d_ptr->fixed_ss->dim, 
-        d_ptr->fixed_ss->origin, d_ptr->fixed_ss->spacing, 
-        d_ptr->fixed_ss->direction_cosines);
-    xform_to_gpuit_bsp (xf_out, xf_in, &pih, stage->grid_spac);
-
     /* Set debugging directory */
     if (stage->debug_dir != "") {
-        bsp_parms->debug = 1;
-        bsp_parms->debug_dir = stage->debug_dir;
-        bsp_parms->debug_stage = stage->stage_no;
+        parms->debug = 1;
+        parms->debug_dir = stage->debug_dir;
+        parms->debug_stage = stage->stage_no;
         logfile_printf ("Set debug directory to %s (%d)\n", 
-            bsp_parms->debug_dir.c_str(), bsp_parms->debug_stage);
+            parms->debug_dir.c_str(), parms->debug_stage);
 
         /* Write fixed, moving, moving_grad */
         std::string fn;
-        fn = string_format ("%s/%02d/moving.mha",
-            bsp_parms->debug_dir.c_str(), bsp_parms->debug_stage);
-        write_mha (fn.c_str(), d_ptr->moving_ss.get());
         fn = string_format ("%s/%02d/fixed.mha",
-            bsp_parms->debug_dir.c_str(), bsp_parms->debug_stage);
-        write_mha (fn.c_str(), d_ptr->fixed_ss.get());
+            parms->debug_dir.c_str(), parms->debug_stage);
+        write_mha (fn.c_str(), 
+            bst->similarity_data.front()->fixed_ss.get());
+        fn = string_format ("%s/%02d/moving.mha",
+            parms->debug_dir.c_str(), parms->debug_stage);
+        write_mha (fn.c_str(),
+            bst->similarity_data.front()->moving_ss.get());
         fn = string_format ("%s/%02d/moving_grad.mha", 
-            bsp_parms->debug_dir.c_str(), bsp_parms->debug_stage);
-        write_mha (fn.c_str(), d_ptr->moving_grad.get());
+            parms->debug_dir.c_str(), parms->debug_stage);
+        write_mha (fn.c_str(), 
+            bst->similarity_data.front()->moving_grad.get());
     }
 }
 
@@ -393,13 +351,12 @@ Bspline_stage::cleanup ()
 
 Xform::Pointer
 do_gpuit_bspline_stage (
-    Registration_parms* regp, 
     Registration_data* regd, 
     const Xform::Pointer& xf_in,
     const Stage_parms* stage)
 {
     Xform::Pointer xf_out = Xform::New ();
-    Bspline_stage pb (regp, regd, stage, xf_in.get());
+    Bspline_stage pb (regd, stage, xf_in.get());
     pb.run_stage ();
     xf_out = pb.d_ptr->xf_out;
     return xf_out;
diff --git a/src/plastimatch/register/bspline_stage.h b/src/plastimatch/register/bspline_stage.h
index f8413ac..7107d20 100644
--- a/src/plastimatch/register/bspline_stage.h
+++ b/src/plastimatch/register/bspline_stage.h
@@ -18,7 +18,6 @@ public:
     Bspline_stage_private *d_ptr;
 public:
     Bspline_stage (
-        Registration_parms *regp, 
         Registration_data *regd, 
         const Stage_parms *stage, 
         Xform *xf_in);
@@ -33,7 +32,6 @@ protected:
 
 Xform::Pointer
 do_gpuit_bspline_stage (
-    Registration_parms* regp, 
     Registration_data* regd, 
     const Xform::Pointer& xf_in, 
     const Stage_parms* stage);
diff --git a/src/plastimatch/register/bspline_state.cxx b/src/plastimatch/register/bspline_state.cxx
index 2071e7f..1cbb039 100644
--- a/src/plastimatch/register/bspline_state.cxx
+++ b/src/plastimatch/register/bspline_state.cxx
@@ -19,7 +19,6 @@
 #include "bspline_interpolate.h"
 #include "bspline_landmarks.h"
 #include "bspline_mi.h"
-#include "bspline_mi_hist.h"
 #include "bspline_mse.h"
 #include "bspline_parms.h"
 #include "bspline_regularize.h"
@@ -28,27 +27,27 @@
 #include "delayload.h"
 #include "file_util.h"
 #include "interpolate_macros.h"
+#include "joint_histogram.h"
 #include "logfile.h"
 #include "plm_math.h"
 #include "string_util.h"
-#include "registration_metric_type.h"
+#include "similarity_metric_type.h"
 #include "volume.h"
 #include "volume_macros.h"
 
 static void
 bspline_cuda_state_create (
-    Bspline_xform* bxf,
+    Bspline_parms *parms,
     Bspline_state *bst,
-    Bspline_parms *parms
+    Bspline_xform* bxf
 );
 static void
 bspline_cuda_state_destroy (
+    Bspline_parms *parms,
     Bspline_state *bst,
-    Bspline_parms *parms, 
-    Bspline_xform *bxf
+    Bspline_xform* bxf
 );
 
-
 class Bspline_state_private 
 {
 public:
@@ -68,11 +67,12 @@ public:
 Bspline_state::Bspline_state ()
 {
     d_ptr = new Bspline_state_private;
+    mi_hist = 0;
 }
 
 Bspline_state::~Bspline_state ()
 {
-    bspline_cuda_state_destroy (this, d_ptr->parms, d_ptr->bxf);
+    bspline_cuda_state_destroy (d_ptr->parms, this, d_ptr->bxf);
     delete d_ptr;
 }
 
@@ -97,62 +97,83 @@ Bspline_state::initialize (
     this->ssd.set_num_coeff (bxf->num_coeff);
 
     if (reg_parms->lambda > 0.0f) {
-        rst->fixed = parms->fixed;
-        rst->moving = parms->moving;
         rst->fixed_stiffness = parms->fixed_stiffness;
         rst->initialize (reg_parms, bxf);
     }
 
     /* Initialize MI histograms */
-    this->mi_hist = 0;
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
-        this->mi_hist = new Bspline_mi_hist_set (
-            parms->mi_hist_type,
-            parms->mi_hist_fixed_bins,
-            parms->mi_hist_moving_bins);
+    printf (">> Checking JH allocation\n");
+    std::list<Metric_state::Pointer>::const_iterator it;
+    for (it = this->similarity_data.begin();
+         it != this->similarity_data.end(); ++it)
+    {
+        const Metric_state::Pointer& ms = *it;
+        if (ms->metric_type == SIMILARITY_METRIC_MI_MATTES) {
+            printf (">> Performing JH allocation\n");
+            ms->mi_hist = new Joint_histogram (
+                parms->mi_hist_type,
+                parms->mi_hist_fixed_bins,
+                parms->mi_hist_moving_bins);
+        }
     }
-    bspline_cuda_state_create (bxf, this, parms);
-
 
-    /* JAS Fix 2011.09.14
-     *   The MI algorithm will get stuck for a set of coefficients all equaling
-     *   zero due to the method we use to compute the cost function gradient.
-     *   However, it is possible we could be inheriting coefficients from a
-     *   prior stage, so we must check for inherited coefficients before
-     *   applying an initial offset to the coefficient array. */
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
-        bool first_iteration = true;
+    /* Landmarks */
+    blm->initialize (bxf);
+}
 
-        for (int i=0; i<bxf->num_coeff; i++) {
-            if (bxf->coeff[i] != 0.0f) {
-                first_iteration = false;
-                break;
-            }
-        }
+void
+Bspline_state::initialize_similarity_images ()
+{
+    /* GCS FIX: The below function also does other initializations 
+       which do not require the similarity images, and therefore could 
+       be done once per stage rather than once per image
+     */
+    /* Copy images into CUDA memory */
+    bspline_cuda_state_create (d_ptr->parms, this, d_ptr->bxf);
+}
 
-        if (first_iteration) {
-            printf ("Initializing 1st MI Stage\n");
-            for (int i = 0; i < bxf->num_coeff; i++) {
-                bxf->coeff[i] = 0.01f;
-            }
+void
+Bspline_state::initialize_mi_histograms ()
+{
+    std::list<Metric_state::Pointer>::const_iterator it;
+    for (it = this->similarity_data.begin();
+         it != this->similarity_data.end(); ++it)
+    {
+        const Metric_state::Pointer& ms = *it;
+        if (ms->metric_type == SIMILARITY_METRIC_MI_MATTES) {
+            printf (">> Performing JH initialization\n");
+            ms->mi_hist->initialize (
+                ms->fixed_ss.get(),
+                ms->moving_ss.get());
         }
     }
+}
 
-    /* Landmarks */
-    blm->initialize (bxf);
+void 
+Bspline_state::set_metric_state (const Metric_state::Pointer& ms)
+{
+    this->fixed = ms->fixed_ss.get();
+    this->moving = ms->moving_ss.get();
+    this->moving_grad = ms->moving_grad.get();
+    this->fixed_roi = ms->fixed_roi.get();
+    this->moving_roi = ms->moving_roi.get();
+    this->mi_hist = ms->mi_hist;
 }
 
 static void
 bspline_cuda_state_create (
-    Bspline_xform* bxf,
-    Bspline_state *bst,           /* Modified in routine */
-    Bspline_parms *parms
+    Bspline_parms *parms,
+    Bspline_state *bst,
+    Bspline_xform *bxf
 )
 {
 #if (CUDA_FOUND)
     if (parms->threading != BTHR_CUDA) {
         return;
     }
+    if (bst->dev_ptrs) {
+        bspline_cuda_state_destroy (parms, bst, bxf);
+    }
 
     /* Set the gpuid */
     LOAD_LIBRARY_SAFE (libplmcuda);
@@ -160,15 +181,17 @@ bspline_cuda_state_create (
     CUDA_selectgpu (parms->gpuid);
     UNLOAD_LIBRARY (libplmcuda);
     
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
     Dev_Pointers_Bspline* dev_ptrs 
         = (Dev_Pointers_Bspline*) malloc (sizeof (Dev_Pointers_Bspline));
     bst->dev_ptrs = dev_ptrs;
-    
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MSE) {
+
+    /* GCS FIX: You cannot have more than one CUDA metric because 
+       dev_ptrs is not defined per metric */
+    if (bst->has_metric_type (SIMILARITY_METRIC_MSE)) {
         /* Be sure we loaded the CUDA plugin */
         LOAD_LIBRARY_SAFE (libplmregistercuda);
         LOAD_SYMBOL (CUDA_bspline_mse_init_j, libplmregistercuda);
@@ -187,7 +210,7 @@ bspline_cuda_state_create (
 
         UNLOAD_LIBRARY (libplmregistercuda);
     } 
-    else if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
+    else if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) {
         /* Be sure we loaded the CUDA plugin */
         LOAD_LIBRARY_SAFE (libplmregistercuda);
         LOAD_SYMBOL (CUDA_bspline_mi_init_a, libplmregistercuda);
@@ -213,8 +236,8 @@ bspline_cuda_state_create (
 
 static void
 bspline_cuda_state_destroy (
-    Bspline_state *bst,
     Bspline_parms *parms, 
+    Bspline_state *bst,
     Bspline_xform *bxf
 )
 {
@@ -223,82 +246,59 @@ bspline_cuda_state_destroy (
         return;
     }
 
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MSE) {
+    if (bst->has_metric_type (SIMILARITY_METRIC_MSE)) {
         LOAD_LIBRARY_SAFE (libplmregistercuda);
         LOAD_SYMBOL (CUDA_bspline_mse_cleanup_j, libplmregistercuda);
         CUDA_bspline_mse_cleanup_j ((Dev_Pointers_Bspline *) bst->dev_ptrs, fixed, moving, moving_grad);
         UNLOAD_LIBRARY (libplmregistercuda);
     }
-    else if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
+    else if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) {
         LOAD_LIBRARY_SAFE (libplmregistercuda);
         LOAD_SYMBOL (CUDA_bspline_mi_cleanup_a, libplmregistercuda);
         CUDA_bspline_mi_cleanup_a ((Dev_Pointers_Bspline *) bst->dev_ptrs, fixed, moving, moving_grad);
         UNLOAD_LIBRARY (libplmregistercuda);
     }
-#endif
+
     free (bst->dev_ptrs);
+    bst->dev_ptrs = 0;
+#endif
 }
 
-Bspline_state *
-bspline_state_create (
-    Bspline_xform *bxf, 
-    Bspline_parms *parms
-)
+bool
+Bspline_state::has_metric_type (Similarity_metric_type metric_type)
 {
-    Bspline_state *bst = (Bspline_state*) malloc (sizeof (Bspline_state));
-    Regularization_parms* reg_parms = parms->reg_parms;
-    Bspline_regularize* rst = &bst->rst;
-    Bspline_landmarks* blm = parms->blm;
-
-    memset (bst, 0, sizeof (Bspline_state));
-    bst->ssd.set_num_coeff (bxf->num_coeff);
-
-    if (reg_parms->lambda > 0.0f) {
-        rst->fixed = parms->fixed;
-        rst->moving = parms->moving;
-        rst->initialize (reg_parms, bxf);
-    }
-
-    /* Initialize MI histograms */
-    bst->mi_hist = 0;
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
-        bst->mi_hist = new Bspline_mi_hist_set (
-            parms->mi_hist_type,
-            parms->mi_hist_fixed_bins,
-            parms->mi_hist_moving_bins);
-    }
-    bspline_cuda_state_create (bxf, bst, parms);
-
-    /* JAS Fix 2011.09.14
-     *   The MI algorithm will get stuck for a set of coefficients all equaling
-     *   zero due to the method we use to compute the cost function gradient.
-     *   However, it is possible we could be inheriting coefficients from a
-     *   prior stage, so we must check for inherited coefficients before
-     *   applying an initial offset to the coefficient array. */
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
-        bool first_iteration = true;
-
-        for (int i=0; i<bxf->num_coeff; i++) {
-            if (bxf->coeff[i] != 0.0f) {
-                first_iteration = false;
-                break;
-            }
-        }
-
-        if (first_iteration) {
-            printf ("Initializing 1st MI Stage\n");
-            for (int i = 0; i < bxf->num_coeff; i++) {
-                bxf->coeff[i] = 0.01f;
-            }
+    std::list<Metric_state::Pointer>::iterator it;
+    for (it = this->similarity_data.begin();
+         it != this->similarity_data.end(); ++it)
+    {
+        if ((*it)->metric_type == metric_type) {
+            return true;
         }
     }
+    return false;
+}
 
-    /* Landmarks */
-    blm->initialize (bxf);
-
-    return bst;
+void
+Bspline_state::log_metric ()
+{
+    printf ("BST METRICS\n");
+    std::list<Metric_state::Pointer>::iterator it;
+    for (it = this->similarity_data.begin();
+         it != this->similarity_data.end(); ++it)
+    {
+        printf ("MET %c%c%c%c%c%c %s %f\n",
+            (*it)->fixed_ss ? '1' : '0',
+            (*it)->moving_ss ? '1' : '0',
+            (*it)->fixed_grad ? '1' : '0',
+            (*it)->moving_grad ? '1' : '0',
+            (*it)->fixed_roi ? '1' : '0',
+            (*it)->moving_roi ? '1' : '0',
+            (*it)->metric_string(),
+            (*it)->metric_lambda
+        );
+    }
 }
diff --git a/src/plastimatch/register/bspline_state.h b/src/plastimatch/register/bspline_state.h
index 18645d7..fbe611b 100644
--- a/src/plastimatch/register/bspline_state.h
+++ b/src/plastimatch/register/bspline_state.h
@@ -5,16 +5,18 @@
 #define _bspline_state_h_
 
 #include "plmregister_config.h"
+#include <list>
 #include <string>
 
-#include "bspline_mi_hist.h"
 #include "bspline_regularize.h"
 #include "bspline_score.h"
+#include "metric_state.h"
 #include "plm_int.h"
 #include "smart_pointer.h"
 
 class Bspline_state_private;
 class Bspline_parms;
+class Joint_histogram;
 
 class PLMREGISTER_API Bspline_state {
 public:
@@ -23,19 +25,44 @@ public:
 public:
     Bspline_state ();
     ~Bspline_state ();
-    void initialize (Bspline_xform *bxf, Bspline_parms *parms);
 public:
     int sm;                         /* Current smetric */
     int it;                         /* Current iterations */
     int feval;                      /* Number of function evaluations */
     Bspline_score ssd;              /* Score and Gradient  */
     void* dev_ptrs;                 /* GPU Device Pointers */
-    Bspline_regularize rst;         /* Analytic regularization */
-    Bspline_mi_hist_set *mi_hist;   /* MI histograms */
+
+    /* Similarity metric */
+    std::list<Metric_state::Pointer> similarity_data;
+
+    /*! \brief Current similarity images.  These are raw pointers 
+     because they are passed to CUDA code.  */
+    Volume *fixed;
+    Volume *moving;
+    Volume *moving_grad;
+    Volume *fixed_roi;
+    Volume *moving_roi;
+    
+    Bspline_regularize rst;
+
+protected:
+    /*! \brief Current joint histogram.  This is raw pointer 
+      because it is passed to CUDA code.  */
+    Joint_histogram *mi_hist;
+
 public:
+    void initialize (Bspline_xform *bxf, Bspline_parms *parms);
+    void initialize_similarity_images ();
+    void initialize_mi_histograms ();
+    void set_metric_state (const Metric_state::Pointer& ms);
     Bspline_score* get_bspline_score () {
         return &ssd;
     }
+    Joint_histogram* get_mi_hist () {
+        return mi_hist;
+    }
+    bool has_metric_type (Similarity_metric_type metric_type);
+    void log_metric ();
 };
 
 #endif
diff --git a/src/plastimatch/register/cuda/CMakeLists.txt b/src/plastimatch/register/cuda/CMakeLists.txt
old mode 100755
new mode 100644
index 1e31bc4..5a10bba
--- a/src/plastimatch/register/cuda/CMakeLists.txt
+++ b/src/plastimatch/register/cuda/CMakeLists.txt
@@ -30,9 +30,6 @@ set (PLMREGISTERCUDA_SRC
 
 set (PLMREGISTERCUDA_IFACE_SRC
   bspline_cuda.cxx
-#  GCS: I hope this can be linked from base instead of duplicated, 
-#  but we'll just have to see.
-#  gaussian.cxx
   )
 
 if (PLM_BUILD_VISCOUS)
diff --git a/src/plastimatch/register/cuda/bspline_cuda.cu b/src/plastimatch/register/cuda/bspline_cuda.cu
index 2174513..16fdc16 100644
--- a/src/plastimatch/register/cuda/bspline_cuda.cu
+++ b/src/plastimatch/register/cuda/bspline_cuda.cu
@@ -12,12 +12,12 @@
 #include "bspline.h"
 #include "bspline_cuda.h"
 #include "bspline_cuda_kernels.h"
-#include "bspline_mi_hist.h"
 #include "bspline_state.h"
 #include "bspline_xform.h"
 #include "cuda_util.h"
 #include "cuda_mem.h"
 #include "cuda_kernel_util.h"
+#include "joint_histogram.h"
 #include "plm_int.h"
 #include "volume.h"
 
@@ -78,7 +78,7 @@ CUDA_bspline_mi_init_a (
     Volume* moving_grad
 )
 {
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
 
     // Keep track of how much memory we allocated in the GPU global memory.
     long unsigned GPU_Memory_Bytes = 0;
@@ -400,7 +400,8 @@ CUDA_bspline_mse_init_j (
     long unsigned GPU_Memory_Bytes = 0;
 
     printf ("Allocating GPU Memory");
-
+    fflush (stdout);
+    
     // Fixed Image (zero copy if possible)
     // ----------------------------------------------------------
     dev_ptrs->fixed_image_size = fixed->npix * fixed->pix_size;
@@ -761,7 +762,7 @@ CUDA_bspline_mi_cleanup_a (
 int
 CUDA_bspline_mi_hist (
     Dev_Pointers_Bspline *dev_ptrs,
-    Bspline_mi_hist_set* mi_hist,
+    Joint_histogram* mi_hist,
     Volume* fixed,
     Volume* moving,
     Bspline_xform* bxf)
@@ -781,7 +782,7 @@ CUDA_bspline_mi_hist (
 void
 CUDA_bspline_mi_hist_fix (
     Dev_Pointers_Bspline *dev_ptrs,
-    Bspline_mi_hist_set* mi_hist,
+    Joint_histogram* mi_hist,
     Volume* fixed,
     Volume* moving,
     Bspline_xform *bxf)
@@ -883,7 +884,7 @@ CUDA_bspline_mi_hist_fix (
 void
 CUDA_bspline_mi_hist_mov (
     Dev_Pointers_Bspline *dev_ptrs,
-    Bspline_mi_hist_set* mi_hist,
+    Joint_histogram* mi_hist,
     Volume* fixed,
     Volume* moving,
     Bspline_xform *bxf)
@@ -986,7 +987,7 @@ CUDA_bspline_mi_hist_mov (
 int
 CUDA_bspline_mi_hist_jnt (
     Dev_Pointers_Bspline *dev_ptrs,
-    Bspline_mi_hist_set* mi_hist,
+    Joint_histogram* mi_hist,
     Volume* fixed,
     Volume* moving,
     Bspline_xform *bxf)
@@ -1157,12 +1158,12 @@ CUDA_bspline_mi_grad (
     Dev_Pointers_Bspline *dev_ptrs
 )
 {
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     GPU_Bspline_Data gbd;
     build_gbd (&gbd, bxf, fixed, moving);
 
     Bspline_score* ssd = &bst->ssd;
-    float* host_grad = ssd->smetric_grad;
+    float* host_grad = ssd->curr_smetric_grad;
 
     if ((mi_hist->fixed.bins > GPU_MAX_BINS) ||
         (mi_hist->moving.bins > GPU_MAX_BINS)) {
diff --git a/src/plastimatch/register/cuda/bspline_cuda.cxx b/src/plastimatch/register/cuda/bspline_cuda.cxx
index 3a98a40..9e4b745 100644
--- a/src/plastimatch/register/cuda/bspline_cuda.cxx
+++ b/src/plastimatch/register/cuda/bspline_cuda.cxx
@@ -125,7 +125,7 @@ bspline_find_correspondence
 
 static inline void
 bspline_mi_hist_add_pvi_8 (
-    Bspline_mi_hist_set* mi_hist, 
+    Joint_histogram* mi_hist, 
     Volume *fixed, 
     Volume *moving, 
     int fv, 
@@ -223,7 +223,7 @@ bspline_mi_hist_add_pvi_8 (
 static inline void
 bspline_mi_pvi_8_dc_dv (
     float dc_dv[3],                /* Output */
-    Bspline_mi_hist_set* mi_hist,      /* Input */
+    Joint_histogram* mi_hist,      /* Input */
     Bspline_state *bst,            /* Input */
     Volume *fixed,                 /* Input */
     Volume *moving,                /* Input */
@@ -300,7 +300,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n1] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw1[0] * dS_dP;
         dc_dv[1] -= dw1[1] * dS_dP;
         dc_dv[2] -= dw1[2] * dS_dP;
@@ -310,7 +310,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n2] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw2[0] * dS_dP;
         dc_dv[1] -= dw2[1] * dS_dP;
         dc_dv[2] -= dw2[2] * dS_dP;
@@ -320,7 +320,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n3] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw3[0] * dS_dP;
         dc_dv[1] -= dw3[1] * dS_dP;
         dc_dv[2] -= dw3[2] * dS_dP;
@@ -330,7 +330,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n4] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw4[0] * dS_dP;
         dc_dv[1] -= dw4[1] * dS_dP;
         dc_dv[2] -= dw4[2] * dS_dP;
@@ -340,7 +340,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n5] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw5[0] * dS_dP;
         dc_dv[1] -= dw5[1] * dS_dP;
         dc_dv[2] -= dw5[2] * dS_dP;
@@ -350,7 +350,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n6] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw6[0] * dS_dP;
         dc_dv[1] -= dw6[1] * dS_dP;
         dc_dv[2] -= dw6[2] * dS_dP;
@@ -360,7 +360,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n7] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw7[0] * dS_dP;
         dc_dv[1] -= dw7[1] * dS_dP;
         dc_dv[2] -= dw7[2] * dS_dP;
@@ -370,7 +370,7 @@ bspline_mi_pvi_8_dc_dv (
     idx_mbin = floor ((m_img[n8] - mi_hist->moving.offset) / mi_hist->moving.delta);
     idx_jbin = offset_fbin + idx_mbin;
     if (j_hist[idx_jbin] > 0.0001) {
-        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->score;
+        dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric;
         dc_dv[0] -= dw8[0] * dS_dP;
         dc_dv[1] -= dw8[1] * dS_dP;
         dc_dv[2] -= dw8[2] * dS_dP;
@@ -408,7 +408,7 @@ bspline_update_grad_b_inline (Bspline_state* bst, Bspline_xform* bxf,
 #endif
 
 #if defined (commentout)
-static void display_hist_totals (Bspline_mi_hist_set *mi_hist)
+static void display_hist_totals (Joint_histogram *mi_hist)
 {
     plm_long i;
     double tmp = 0;
@@ -433,7 +433,7 @@ static void display_hist_totals (Bspline_mi_hist_set *mi_hist)
 
 ////////////////////////////////////////////////////////////////////////////////
 size_t
-CPU_MI_Hist (Bspline_mi_hist_set *mi_hist,  // OUTPUT: Histograms
+CPU_MI_Hist (Joint_histogram *mi_hist,  // OUTPUT: Histograms
     Bspline_xform *bxf,                 //  INPUT: Bspline X-Form
     Volume* fixed,                      //  INPUT: Fixed Image
     Volume* moving)                     //  INPUT: Moving Image
@@ -504,7 +504,7 @@ CPU_MI_Hist (Bspline_mi_hist_set *mi_hist,  // OUTPUT: Histograms
 
 
 static float
-CPU_MI_Score (Bspline_mi_hist_set* mi_hist, int num_vox)
+CPU_MI_Score (Joint_histogram* mi_hist, int num_vox)
 {
     double* f_hist = mi_hist->f_hist;
     double* m_hist = mi_hist->m_hist;
@@ -530,7 +530,7 @@ CPU_MI_Score (Bspline_mi_hist_set* mi_hist, int num_vox)
 
 #if defined (MI_GRAD_CPU)
 void
-CPU_MI_Grad (Bspline_mi_hist_set *mi_hist, // OUTPUT: Histograms
+CPU_MI_Grad (Joint_histogram *mi_hist, // OUTPUT: Histograms
         Bspline_state *bst,     //  INPUT: Bspline State
         Bspline_xform *bxf,     //  INPUT: Bspline X-Form
         Volume* fixed,          //  INPUT: Fixed Image
@@ -611,16 +611,16 @@ CUDA_bspline_mi_a (
     Bspline_xform *bxf
 )
 {
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
     UNUSED_VARIABLE (moving_grad);
 
     Dev_Pointers_Bspline* dev_ptrs = (Dev_Pointers_Bspline*)bst->dev_ptrs;
 
     // --- DECLARE LOCAL VARIABLES ------------------------------
     Bspline_score* ssd; // Holds the SSD "Score" information
-    Bspline_mi_hist_set* mi_hist = bst->mi_hist;
+    Joint_histogram* mi_hist = bst->get_mi_hist();
     double* f_hist = mi_hist->f_hist;
     double* m_hist = mi_hist->m_hist;
     double* j_hist = mi_hist->j_hist;
@@ -674,9 +674,9 @@ CUDA_bspline_mi_a (
     if ((mi_hist->fixed.bins > GPU_MAX_BINS) ||
         (mi_hist->moving.bins > GPU_MAX_BINS)) {
 
-        ssd->num_vox = CPU_MI_Hist (mi_hist, bxf, fixed, moving);
+        ssd->curr_num_vox = CPU_MI_Hist (mi_hist, bxf, fixed, moving);
     } else {
-        ssd->num_vox = CUDA_bspline_mi_hist (dev_ptrs, mi_hist, fixed, moving, bxf);
+        ssd->curr_num_vox = CUDA_bspline_mi_hist (dev_ptrs, mi_hist, fixed, moving, bxf);
     }
     // ----------------------------------------------------------
 
@@ -698,7 +698,7 @@ CUDA_bspline_mi_a (
 
     // --- COMPUTE SCORE ----------------------------------------
 #if defined (MI_SCORE_CPU)
-    ssd->smetric[0] = CPU_MI_Score(mi_hist, ssd->num_vox);
+    ssd->curr_smetric = CPU_MI_Score(mi_hist, ssd->curr_num_vox);
 #else
     // Doing this on the GPU may be silly.
     // The CPU generally completes this computation extremely quickly
@@ -709,13 +709,13 @@ CUDA_bspline_mi_a (
 #if defined (MI_GRAD_CPU)
     CPU_MI_Grad(mi_hist, bst, bxf, fixed, moving, (float)ssd->num_vox);
 #else
-    float score = ssd->smetric[0];
+    float score = ssd->curr_smetric;
     CUDA_bspline_mi_grad (
         bst,
         bxf,
         fixed,
         moving,
-        (float)ssd->num_vox,
+        (float) ssd->curr_num_vox,
         score,
         dev_ptrs
     );
@@ -727,8 +727,6 @@ CUDA_bspline_mi_a (
     }
 }
 
-
-
 void
 CUDA_bspline_mse_j (
     Bspline_parms *parms,
@@ -736,9 +734,9 @@ CUDA_bspline_mse_j (
     Bspline_xform *bxf
 )
 {
-    Volume *fixed = parms->fixed;
-    Volume *moving = parms->moving;
-    Volume *moving_grad = parms->moving_grad;
+    Volume *fixed = bst->fixed;
+    Volume *moving = bst->moving;
+    Volume *moving_grad = bst->moving_grad;
 
     Dev_Pointers_Bspline* dev_ptrs = (Dev_Pointers_Bspline*)bst->dev_ptrs;
 
@@ -789,12 +787,12 @@ CUDA_bspline_mse_j (
         fixed,
         bxf->vox_per_rgn,
         fixed->dim,
-        &(ssd->smetric[0]),
-        bst->ssd.smetric_grad,
+        &(ssd->curr_smetric),
+        bst->ssd.curr_smetric_grad,
         &ssd_grad_mean,
         &ssd_grad_norm,
         dev_ptrs,
-        &(ssd->num_vox)
+        &(ssd->curr_num_vox)
     );
 
     if (parms->debug) {
diff --git a/src/plastimatch/register/cuda/bspline_cuda.h b/src/plastimatch/register/cuda/bspline_cuda.h
index d8e73e7..8588ed1 100644
--- a/src/plastimatch/register/cuda/bspline_cuda.h
+++ b/src/plastimatch/register/cuda/bspline_cuda.h
@@ -30,7 +30,7 @@
 /* HARDWARE IMPOSED CONSTANTS */
 #define GPU_MAX_BINS 32
 
-class Bspline_mi_hist_set;
+class Joint_histogram;
 class Bspline_optimize;
 class Bspline_parms;
 class Bspline_state;
@@ -278,7 +278,7 @@ extern "C" {
     int
     CUDA_bspline_mi_hist (
         Dev_Pointers_Bspline *dev_ptrs,
-        Bspline_mi_hist_set* mi_hist,
+        Joint_histogram* mi_hist,
         Volume* fixed,
         Volume* moving,
         Bspline_xform *bxf
@@ -287,7 +287,7 @@ extern "C" {
     void
     CUDA_bspline_mi_hist_fix (
         Dev_Pointers_Bspline *dev_ptrs,
-        Bspline_mi_hist_set* mi_hist,
+        Joint_histogram* mi_hist,
         Volume* fixed,
         Volume* moving,
         Bspline_xform *bxf
@@ -296,7 +296,7 @@ extern "C" {
     void
     CUDA_bspline_mi_hist_mov (
         Dev_Pointers_Bspline *dev_ptrs,
-        Bspline_mi_hist_set* mi_hist,
+        Joint_histogram* mi_hist,
         Volume* fixed,
         Volume* moving,
         Bspline_xform *bxf
@@ -305,7 +305,7 @@ extern "C" {
     int
     CUDA_bspline_mi_hist_jnt (
         Dev_Pointers_Bspline *dev_ptrs,
-        Bspline_mi_hist_set* mi_hist,
+        Joint_histogram* mi_hist,
         Volume* fixed,
         Volume* moving,
         Bspline_xform *bxf
diff --git a/src/plastimatch/register/gpuit_demons.cxx b/src/plastimatch/register/gpuit_demons.cxx
index dd3fe32..103d0e1 100644
--- a/src/plastimatch/register/gpuit_demons.cxx
+++ b/src/plastimatch/register/gpuit_demons.cxx
@@ -29,8 +29,10 @@ do_gpuit_demons_stage_internal (
     Demons_parms parms;
     Plm_image_header pih;
 
-    Volume::Pointer& fixed = regd->fixed_image->get_volume_float ();
-    Volume::Pointer& moving = regd->moving_image->get_volume_float ();
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
+    Volume::Pointer& fixed = fixed_image->get_volume_float ();
+    Volume::Pointer& moving = moving_image->get_volume_float ();
     Volume::Pointer moving_ss;
     Volume::Pointer fixed_ss;
     Volume::Pointer moving_grad;
diff --git a/src/plastimatch/register/bspline_gm.h b/src/plastimatch/register/groupwise_parms.cxx
old mode 100755
new mode 100644
similarity index 65%
copy from src/plastimatch/register/bspline_gm.h
copy to src/plastimatch/register/groupwise_parms.cxx
index 8520890..5d4fa8e
--- a/src/plastimatch/register/bspline_gm.h
+++ b/src/plastimatch/register/groupwise_parms.cxx
@@ -1,13 +1,14 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _bspline_gm_h_
-#define _bspline_gm_h_
-
 #include "plmregister_config.h"
 
-class Bspline_optimize;
+#include "groupwise_parms.h"
 
-PLMREGISTER_API void bspline_score_gm (Bspline_optimize *bod);
+Groupwise_parms::Groupwise_parms()
+{
+}
 
-#endif
+Groupwise_parms::~Groupwise_parms()
+{
+}
diff --git a/src/plastimatch/register/bspline_gm.h b/src/plastimatch/register/groupwise_parms.h
old mode 100755
new mode 100644
similarity index 62%
copy from src/plastimatch/register/bspline_gm.h
copy to src/plastimatch/register/groupwise_parms.h
index 8520890..0c69eb3
--- a/src/plastimatch/register/bspline_gm.h
+++ b/src/plastimatch/register/groupwise_parms.h
@@ -1,13 +1,17 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _bspline_gm_h_
-#define _bspline_gm_h_
+#ifndef _groupwise_parms_h_
+#define _groupwise_parms_h_
 
 #include "plmregister_config.h"
 
-class Bspline_optimize;
+class PLMREGISTER_API Groupwise_parms {
+public:
+    Groupwise_parms ();
+    ~Groupwise_parms ();
 
-PLMREGISTER_API void bspline_score_gm (Bspline_optimize *bod);
+public:
+};
 
 #endif
diff --git a/src/plastimatch/register/histogram.cxx b/src/plastimatch/register/histogram.cxx
new file mode 100644
index 0000000..a564505
--- /dev/null
+++ b/src/plastimatch/register/histogram.cxx
@@ -0,0 +1,33 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmregister_config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "file_util.h"
+#include "histogram.h"
+#include "logfile.h"
+#include "plm_math.h"
+#include "print_and_exit.h"
+#include "string_util.h"
+#include "volume.h"
+
+Histogram::Histogram (
+    Mi_hist_type type,
+    plm_long bins)
+{
+    this->type = type;
+    this->bins = bins;
+    this->offset = 0.f;
+    this->big_bin = 0;
+    this->delta = 0.f;
+    this->keys = 0;
+    this->key_lut = 0;
+}
+
+Histogram::~Histogram ()
+{
+    if (this->key_lut) {
+        free (this->key_lut);
+    }
+}
diff --git a/src/plastimatch/register/histogram.h b/src/plastimatch/register/histogram.h
new file mode 100644
index 0000000..ad085c4
--- /dev/null
+++ b/src/plastimatch/register/histogram.h
@@ -0,0 +1,38 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _histogram_h_
+#define _histogram_h_
+
+#include "plmregister_config.h"
+#include <string>
+#include "plm_int.h"
+
+/* Maximum # of bins for a vopt histogram */
+#define VOPT_RES 1000
+
+enum Mi_hist_type {
+    HIST_EQSP,
+    HIST_VOPT
+};
+
+class PLMREGISTER_API Histogram {
+public:
+    Histogram (
+        Mi_hist_type type = HIST_EQSP, 
+        plm_long bins = 32);
+    ~Histogram ();
+public:
+    /* Used by all histogram types */
+    enum Mi_hist_type type;   /* Type of histograms */
+    plm_long bins;                    /* # of bins in histogram  */
+    float offset;                     /* minimum voxel intensity */
+    plm_long big_bin;                 /* fullest bin index       */
+    float delta;                      /* bin OR key spacing   */
+
+    /* For V-Optimal Histograms */
+    plm_long keys;                    /* # of keys               */
+    int* key_lut;                     /* bin keys lookup table   */
+};
+
+#endif
diff --git a/src/plastimatch/register/itk_align_center.cxx b/src/plastimatch/register/itk_align_center.cxx
index 378b7b4..a50dc97 100644
--- a/src/plastimatch/register/itk_align_center.cxx
+++ b/src/plastimatch/register/itk_align_center.cxx
@@ -26,10 +26,12 @@ itk_align_center (
     Registration_data* regd, Xform *xf_out, 
     const Xform *xf_in, const Stage_parms* stage)
 {
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
     float fixed_center[3];
     float moving_center[3];
-    itk_volume_center (fixed_center, regd->fixed_image->itk_float());
-    itk_volume_center (moving_center, regd->moving_image->itk_float());
+    itk_volume_center (fixed_center, fixed_image->itk_float());
+    itk_volume_center (moving_center, moving_image->itk_float());
 
     itk::Array<double> trn_parms (3);
     trn_parms[0] = moving_center[0] - fixed_center[0];
@@ -43,15 +45,18 @@ itk_align_center_of_gravity (
     Registration_data* regd, Xform *xf_out, 
     const Xform *xf_in, const Stage_parms* stage)
 {
-    if (regd->fixed_roi != NULL && regd->moving_roi != NULL) {
-        typedef itk::ImageMomentsCalculator<UCharImageType> ImageMomentsCalculatorType;
-        
-        ImageMomentsCalculatorType::Pointer fixedCalculator = ImageMomentsCalculatorType::New();
-        fixedCalculator->SetImage(regd->fixed_roi->itk_uchar());
+    if (regd->get_fixed_roi() && regd->get_moving_roi()) {
+        typedef itk::ImageMomentsCalculator<UCharImageType>
+            ImageMomentsCalculatorType;
+
+        ImageMomentsCalculatorType::Pointer fixedCalculator
+            = ImageMomentsCalculatorType::New();
+        fixedCalculator->SetImage(regd->get_fixed_roi()->itk_uchar());
         fixedCalculator->Compute();
 
-        ImageMomentsCalculatorType::Pointer movingCalculator = ImageMomentsCalculatorType::New();
-        movingCalculator->SetImage(regd->moving_roi->itk_uchar());
+        ImageMomentsCalculatorType::Pointer movingCalculator
+            = ImageMomentsCalculatorType::New();
+        movingCalculator->SetImage(regd->get_moving_roi()->itk_uchar());
         movingCalculator->Compute();
 
         ImageMomentsCalculatorType::VectorType fixedCenter; 
diff --git a/src/plastimatch/register/itk_demons.cxx b/src/plastimatch/register/itk_demons.cxx
index 12b2aa6..a097b1a 100644
--- a/src/plastimatch/register/itk_demons.cxx
+++ b/src/plastimatch/register/itk_demons.cxx
@@ -88,31 +88,31 @@ set_and_subsample_masks (
     const Stage_parms* stage)
 {
     /* Subsample fixed & moving images */
-    if(regd->fixed_roi)
+    if (regd->get_fixed_roi())
     {
-      MaskType::Pointer fixedSpatialObjectMask = MaskType::New();
-      UCharImageType::Pointer fixed_mask
-        = subsample_image (regd->fixed_roi->itk_uchar(),
-        stage->resample_rate_fixed[0],
-        stage->resample_rate_fixed[1],
-        stage->resample_rate_fixed[2],
-        0);
-      fixedSpatialObjectMask->SetImage(fixed_mask);
-      fixedSpatialObjectMask->Update();
-      m_filter->SetFixedImageMask (fixedSpatialObjectMask);
+        MaskType::Pointer fixedSpatialObjectMask = MaskType::New();
+        UCharImageType::Pointer fixed_mask
+            = subsample_image (regd->get_fixed_roi()->itk_uchar(),
+                stage->resample_rate_fixed[0],
+                stage->resample_rate_fixed[1],
+                stage->resample_rate_fixed[2],
+                0);
+        fixedSpatialObjectMask->SetImage(fixed_mask);
+        fixedSpatialObjectMask->Update();
+        m_filter->SetFixedImageMask (fixedSpatialObjectMask);
     }
-    if(regd->moving_roi)
+    if(regd->get_moving_roi())
     {
-      MaskType::Pointer movingSpatialObjectMask = MaskType::New();
-      UCharImageType::Pointer moving_mask
-        = subsample_image (regd->moving_roi->itk_uchar(),
-        stage->resample_rate_fixed[0],
-        stage->resample_rate_fixed[1],
-        stage->resample_rate_fixed[2],
-        0);
-      movingSpatialObjectMask->SetImage(moving_mask);
-      movingSpatialObjectMask->Update();
-      m_filter->SetMovingImageMask(movingSpatialObjectMask);
+        MaskType::Pointer movingSpatialObjectMask = MaskType::New();
+        UCharImageType::Pointer moving_mask
+            = subsample_image (regd->get_moving_roi()->itk_uchar(),
+                stage->resample_rate_fixed[0],
+                stage->resample_rate_fixed[1],
+                stage->resample_rate_fixed[2],
+                0);
+        movingSpatialObjectMask->SetImage(moving_mask);
+        movingSpatialObjectMask->Update();
+        m_filter->SetMovingImageMask(movingSpatialObjectMask);
     }
 }
 
@@ -133,30 +133,31 @@ do_demons_stage_internal (
     const Stage_parms* stage)
 {
     /* Subsample fixed & moving images */
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
     FloatImageType::Pointer fixed_ss
-    = subsample_image (regd->fixed_image->itk_float(),
-        stage->resample_rate_fixed[0],
-        stage->resample_rate_fixed[1],
-        stage->resample_rate_fixed[2],
-        stage->default_value);
+        = subsample_image (fixed_image->itk_float(),
+            stage->resample_rate_fixed[0],
+            stage->resample_rate_fixed[1],
+            stage->resample_rate_fixed[2],
+            stage->default_value);
     FloatImageType::Pointer moving_ss
-    = subsample_image (regd->moving_image->itk_float(),
-        stage->resample_rate_moving[0],
-        stage->resample_rate_moving[1],
-        stage->resample_rate_moving[2],
-        stage->default_value);
-
-    if(stage->histoeq)
-      {
+        = subsample_image (moving_image->itk_float(),
+            stage->resample_rate_moving[0],
+            stage->resample_rate_moving[1],
+            stage->resample_rate_moving[2],
+            stage->default_value);
+
+    if (stage->histoeq) {
         histo_equ=HistogramMatchingFilter::New();
         histo_equ->SetInput(moving_ss);
         histo_equ->SetReferenceImage(fixed_ss);
         histo_equ->SetNumberOfHistogramLevels(stage->num_hist_levels);
         histo_equ->SetNumberOfMatchPoints(stage->num_matching_points);
         m_filter->SetMovingImage (histo_equ->GetOutput());
-      }
-    else
-      m_filter->SetMovingImage (moving_ss);
+    } else {
+        m_filter->SetMovingImage (moving_ss);
+    }
 
     m_filter->SetFixedImage (fixed_ss);
 
@@ -164,8 +165,8 @@ do_demons_stage_internal (
     if (xf_in->m_type != XFORM_NONE) {
 	xform_to_itk_vf (xf_out, xf_in, fixed_ss);
 
-    //Set initial deformation field
-    m_filter->SetInput (xf_out->get_itk_vf());
+        //Set initial deformation field
+        m_filter->SetInput (xf_out->get_itk_vf());
     }
 
     if (stage->max_its <= 0) {
diff --git a/src/plastimatch/register/itk_registration.cxx b/src/plastimatch/register/itk_registration.cxx
index 18ae8d4..b43313e 100644
--- a/src/plastimatch/register/itk_registration.cxx
+++ b/src/plastimatch/register/itk_registration.cxx
@@ -33,10 +33,12 @@
 #include "itk_registration_private.h"
 #include "itk_resample.h"
 #include "logfile.h"
+#include "metric_parms.h"
 #include "plm_image.h"
 #include "plm_image_header.h"
 #include "print_and_exit.h"
 #include "registration_data.h"
+#include "registration_util.h"
 #include "shared_parms.h"
 #include "stage_parms.h"
 #include "xform.h"
@@ -145,18 +147,16 @@ Itk_registration_private::compute_num_samples (
         lprintf ("Setting spatial samples to %d\n",
             stage->mi_num_spatial_samples);
         return stage->mi_num_spatial_samples;
-    } else {
-        plm_long dim[3], num_voxels;
-        get_image_header (dim, 0, 0, fixed_ss);
-        num_voxels = dim[0] * dim[1] * dim[2];
-        unsigned int num_samples 
-            = stage->mi_num_spatial_samples_pct * num_voxels;
-        lprintf ("Setting spatial samples to %f x %d = %u\n",
-            stage->mi_num_spatial_samples_pct, (int) num_voxels,
-            (unsigned int) 
-            (stage->mi_num_spatial_samples_pct * num_voxels));
-        return num_samples;
-    } 
+    }
+
+    plm_long num_voxels = count_fixed_voxels (regd, stage, fixed_ss);
+    unsigned int num_samples 
+        = stage->mi_num_spatial_samples_pct * num_voxels;
+    lprintf ("Setting spatial samples to %f x %d = %u\n",
+        stage->mi_num_spatial_samples_pct, (int) num_voxels,
+        (unsigned int) 
+        (stage->mi_num_spatial_samples_pct * num_voxels));
+    return num_samples;
 }
 
 void
@@ -202,14 +202,25 @@ Itk_registration_private::set_best_xform ()
 void
 Itk_registration_private::set_metric (FloatImageType::Pointer& fixed_ss)
 {
-    switch (stage->metric_type[0]) {
-    case REGISTRATION_METRIC_MSE:
+    /* GCS FIX, split metric vector into separate items in 
+       Stage_similarity_data list */
+    Metric_parms metric_parms;
+    const Shared_parms *shared = stage->get_shared_parms();
+    std::map<std::string,Metric_parms>::const_iterator metric_it;
+    for (metric_it = shared->metric.begin();
+         metric_it != shared->metric.end(); ++metric_it) {
+        metric_parms = metric_it->second;
+        break;
+    }
+    
+    switch (metric_parms.metric_type) {
+    case SIMILARITY_METRIC_MSE:
     {
         MSEMetricType::Pointer metric = MSEMetricType::New();
         registration->SetMetric(metric);
     }
     break;
-    case REGISTRATION_METRIC_MI_VW:
+    case SIMILARITY_METRIC_MI_VW:
     {
         /*  The metric requires a number of parameters to be
             selected, including the standard deviation of the
@@ -229,7 +240,7 @@ Itk_registration_private::set_metric (FloatImageType::Pointer& fixed_ss)
         registration->SetMetric(metric);
     }
     break;
-    case REGISTRATION_METRIC_MI_MATTES:
+    case SIMILARITY_METRIC_MI_MATTES:
     {
         /*  The metric requires two parameters to be selected: the 
             number of bins used to compute the entropy and the
@@ -263,7 +274,7 @@ Itk_registration_private::set_metric (FloatImageType::Pointer& fixed_ss)
         registration->SetMetric(metric);
     }
     break;
-    case REGISTRATION_METRIC_NMI:
+    case SIMILARITY_METRIC_NMI:
     {
         NMIMetricType::Pointer metric = NMIMetricType::New();
 
@@ -308,15 +319,15 @@ void
 Itk_registration_private::set_roi_images ()
 {
     const Shared_parms *shared = stage->get_shared_parms();
-    if (shared->fixed_roi_enable && regd->fixed_roi) {
+    if (shared->fixed_roi_enable && regd->get_fixed_roi()) {
         Mask_SOType::Pointer roi_so = Mask_SOType::New();
-        roi_so->SetImage(regd->fixed_roi->itk_uchar());
+        roi_so->SetImage(regd->get_fixed_roi()->itk_uchar());
         roi_so->Update();
         registration->GetMetric()->SetFixedImageMask (roi_so);
     }
-    if (shared->moving_roi_enable && regd->moving_roi) {
+    if (shared->moving_roi_enable && regd->get_moving_roi()) {
         Mask_SOType::Pointer roi_so = Mask_SOType::New();
-        roi_so->SetImage(regd->moving_roi->itk_uchar());
+        roi_so->SetImage(regd->get_moving_roi()->itk_uchar());
         roi_so->Update();
         registration->GetMetric()->SetMovingImageMask (roi_so);
     }
@@ -680,14 +691,16 @@ itk_registration_stage (
     irp.registration = RegistrationType::New();
 
     /* Subsample fixed & moving images */
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
     FloatImageType::Pointer fixed_ss = subsample_image (
-        regd->fixed_image->itk_float(), 
+        fixed_image->itk_float(), 
         stage->resample_rate_fixed[0], 
         stage->resample_rate_fixed[1], 
         stage->resample_rate_fixed[2], 
         stage->default_value);
     FloatImageType::Pointer moving_ss = subsample_image (
-        regd->moving_image->itk_float(), 
+        moving_image->itk_float(), 
         stage->resample_rate_moving[0], 
         stage->resample_rate_moving[1], 
         stage->resample_rate_moving[2], 
@@ -742,10 +755,12 @@ itk_align_center (
     Registration_data* regd, Xform *xf_out, 
     const Xform *xf_in, const Stage_parms* stage)
 {
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
     float fixed_center[3];
     float moving_center[3];
-    itk_volume_center (fixed_center, regd->fixed_image->itk_float());
-    itk_volume_center (moving_center, regd->moving_image->itk_float());
+    itk_volume_center (fixed_center, fixed_image->itk_float());
+    itk_volume_center (moving_center, moving_image->itk_float());
 
     itk::Array<double> trn_parms (3);
     trn_parms[0] = moving_center[0] - fixed_center[0];
@@ -760,15 +775,15 @@ itk_align_center_of_gravity (
     const Xform *xf_in, const Stage_parms* stage)
 {
 
-    if (regd->fixed_roi != NULL && regd->moving_roi != NULL) {
+    if (regd->get_fixed_roi() && regd->get_moving_roi()) {
         typedef itk::ImageMomentsCalculator<UCharImageType> ImageMomentsCalculatorType;
         
         ImageMomentsCalculatorType::Pointer fixedCalculator = ImageMomentsCalculatorType::New();
-        fixedCalculator->SetImage(regd->fixed_roi->itk_uchar());
+        fixedCalculator->SetImage(regd->get_fixed_roi()->itk_uchar());
         fixedCalculator->Compute();
 
         ImageMomentsCalculatorType::Pointer movingCalculator = ImageMomentsCalculatorType::New();
-        movingCalculator->SetImage(regd->moving_roi->itk_uchar());
+        movingCalculator->SetImage(regd->get_moving_roi()->itk_uchar());
         movingCalculator->Compute();
 
         ImageMomentsCalculatorType::VectorType fixedCenter; 
diff --git a/src/plastimatch/register/itk_registration_observer.cxx b/src/plastimatch/register/itk_registration_observer.cxx
index 0756eac..25e2fde 100644
--- a/src/plastimatch/register/itk_registration_observer.cxx
+++ b/src/plastimatch/register/itk_registration_observer.cxx
@@ -14,8 +14,10 @@
 #include "itk_registration.h"
 #include "itk_registration_private.h"
 #include "logfile.h"
+#include "metric_parms.h"
 #include "plm_math.h"
 #include "plm_timer.h"
+#include "shared_parms.h"
 #include "stage_parms.h"
 
 /* Lots of ITK algorithms don't behave uniformly.
@@ -80,6 +82,17 @@ public:
     void
     Execute (const itk::Object * object, const itk::EventObject & event)
     {
+        /* GCS FIX, split metric vector into separate items in 
+           Stage_similarity_data list */
+        Metric_parms metric_parms;
+        const Shared_parms *shared = irp->stage->get_shared_parms();
+        std::map<std::string,Metric_parms>::const_iterator metric_it;
+        for (metric_it = shared->metric.begin();
+             metric_it != shared->metric.end(); ++metric_it) {
+            metric_parms = metric_it->second;
+            break;
+        }
+        
         if (typeid(event) == typeid(itk::StartEvent)) {
             m_feval = 0;
             m_prev_value = -DBL_MAX;
@@ -115,8 +128,8 @@ public:
             double duration = timer->report ();
 
             lprintf ("%s [%2d,%3d] %9.3f [%6.3f secs]\n", 
-                (irp->stage->metric_type[0] == REGISTRATION_METRIC_MSE)
-                  ? "MSE" : "MI",
+                (metric_parms.metric_type == SIMILARITY_METRIC_MSE)
+                ? "MSE" : "MI",
                 it, m_feval, val, duration);
             timer->start ();
             m_feval++;
@@ -139,13 +152,13 @@ public:
             /* Print out score & optimizer stats */
             if (irp->stage->optim_type == OPTIMIZATION_AMOEBA) {
                 lprintf ("%s [%3d] %9.3f ",
-                    (irp->stage->metric_type[0] == REGISTRATION_METRIC_MSE) 
-                      ? "MSE" : "MI",
+                    (metric_parms.metric_type == SIMILARITY_METRIC_MSE) 
+                    ? "MSE" : "MI",
                     m_feval / 2, val);
             } else {
                 lprintf ("%s [%2d,%3d,%5.2f] %9.3f ",
-                    (irp->stage->metric_type[0] == REGISTRATION_METRIC_MSE) 
-                      ? "MSE" : "MI",
+                    (metric_parms.metric_type == SIMILARITY_METRIC_MSE) 
+                    ? "MSE" : "MI",
                     it, m_feval, ss, val);
             }
 
diff --git a/src/plastimatch/register/bspline_mi_hist.cxx b/src/plastimatch/register/joint_histogram.cxx
old mode 100755
new mode 100644
similarity index 67%
rename from src/plastimatch/register/bspline_mi_hist.cxx
rename to src/plastimatch/register/joint_histogram.cxx
index 8758728..54584b3
--- a/src/plastimatch/register/bspline_mi_hist.cxx
+++ b/src/plastimatch/register/joint_histogram.cxx
@@ -4,45 +4,23 @@
 #include "plmregister_config.h"
 #include <stdio.h>
 #include <stdlib.h>
-#include "bspline_mi_hist.h"
 #include "file_util.h"
+#include "joint_histogram.h"
 #include "logfile.h"
 #include "plm_math.h"
 #include "print_and_exit.h"
 #include "string_util.h"
 #include "volume.h"
+#include "xpm.h"
 
-Bspline_mi_hist::Bspline_mi_hist (
-    Mi_hist_type type,
-    plm_long bins)
-{
-    //this->type = HIST_EQSP;
-    //this->bins = 32;
-    this->type = type;
-    this->bins = bins;
-    this->offset = 0.f;
-    this->big_bin = 0;
-    this->delta = 0.f;
-
-    this->keys = 0;
-    this->key_lut = 0;
-}
-
-Bspline_mi_hist::~Bspline_mi_hist ()
-{
-    if (this->key_lut) {
-        free (this->key_lut);
-    }
-}
-
-Bspline_mi_hist_set::Bspline_mi_hist_set ()
+Joint_histogram::Joint_histogram ()
 {
     this->m_hist = 0;
     this->f_hist = 0;
     this->j_hist = 0;
 }
 
-Bspline_mi_hist_set::Bspline_mi_hist_set (Mi_hist_type type,
+Joint_histogram::Joint_histogram (Mi_hist_type type,
     plm_long fixed_bins, plm_long moving_bins)
     : moving (type, moving_bins), 
       fixed (type, fixed_bins), 
@@ -51,7 +29,7 @@ Bspline_mi_hist_set::Bspline_mi_hist_set (Mi_hist_type type,
     this->allocate ();
 }
 
-Bspline_mi_hist_set::~Bspline_mi_hist_set ()
+Joint_histogram::~Joint_histogram ()
 {
     delete[] this->f_hist;
     delete[] this->m_hist;
@@ -59,7 +37,7 @@ Bspline_mi_hist_set::~Bspline_mi_hist_set ()
 }
 
 void 
-Bspline_mi_hist_set::allocate ()
+Joint_histogram::allocate ()
 {
     this->m_hist = new double [this->moving.bins]();
     this->f_hist = new double [this->fixed.bins]();
@@ -68,7 +46,7 @@ Bspline_mi_hist_set::allocate ()
 
 
 void 
-Bspline_mi_hist_set::reset_histograms ()
+Joint_histogram::reset_histograms ()
 {
     memset (this->f_hist, 0, this->fixed.bins * sizeof(double));
     memset (this->m_hist, 0, this->moving.bins * sizeof(double));
@@ -104,7 +82,7 @@ vopt_bin_error (int start, int end, double* s_lut, double* ssq_lut, double* cnt_
 static void
 bspline_initialize_mi_bigbin (
     double* hist, 
-    Bspline_mi_hist* hparms, 
+    Histogram* hparms, 
     Volume* vol
 )
 {
@@ -135,7 +113,7 @@ bspline_initialize_mi_bigbin (
 }
 
 static void
-bspline_initialize_mi_hist_eqsp (Bspline_mi_hist* hparms, Volume* vol)
+bspline_initialize_mi_hist_eqsp (Histogram* hparms, Volume* vol)
 {
     plm_long i;
     float min_vox, max_vox;
@@ -215,7 +193,7 @@ bspline_mi_hist_vopt_dump_ranges (
  *   http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.92.3195&rep=rep1&type=pdf
  */
 static void
-bspline_initialize_mi_hist_vopt (Bspline_mi_hist* hparms, Volume* vol)
+bspline_initialize_mi_hist_vopt (Histogram* hparms, Volume* vol)
 {
     int idx_bin;
     plm_long curr, next, bottom;
@@ -347,7 +325,7 @@ bspline_initialize_mi_hist_vopt (Bspline_mi_hist* hparms, Volume* vol)
 
 
 static void
-bspline_initialize_mi_hist (Bspline_mi_hist* hparms, Volume* vol)
+bspline_initialize_mi_hist (Histogram* hparms, Volume* vol)
 {
     /* If user wants more than VOPT can offer, fallback to EQSP */
     if ((hparms->bins > VOPT_RES) && (hparms->type == HIST_VOPT)) {
@@ -370,7 +348,7 @@ bspline_initialize_mi_hist (Bspline_mi_hist* hparms, Volume* vol)
 }
 
 void
-Bspline_mi_hist_set::initialize (Volume *fixed, Volume *moving)
+Joint_histogram::initialize (Volume *fixed, Volume *moving)
 {
     bspline_initialize_mi_hist (&this->fixed, fixed);
     bspline_initialize_mi_hist (&this->moving, moving);
@@ -393,7 +371,7 @@ Bspline_mi_hist_set::initialize (Volume *fixed, Volume *moving)
 }
 
 void
-Bspline_mi_hist_set::dump_hist (int it, const std::string& prefix)
+Joint_histogram::dump_hist (int it, const std::string& prefix)
 {
     double* f_hist = this->f_hist;
     double* m_hist = this->m_hist;
@@ -443,7 +421,7 @@ Bspline_mi_hist_set::dump_hist (int it, const std::string& prefix)
 }
 
 void
-Bspline_mi_hist_set::add_pvi_8
+Joint_histogram::add_pvi_8
 (
     const Volume *fixed, 
     const Volume *moving, 
@@ -510,7 +488,7 @@ Bspline_mi_hist_set::add_pvi_8
 
 /* This algorithm uses a un-normalized score. */
 float
-Bspline_mi_hist_set::compute_score (int num_vox)
+Joint_histogram::compute_score (int num_vox)
 {
     double* f_hist = this->f_hist;
     double* m_hist = this->m_hist;
@@ -535,3 +513,211 @@ Bspline_mi_hist_set::compute_score (int num_vox)
     score = score / fnv;
     return (float) score;
 }
+
+void dump_xpm_hist (Joint_histogram* mi_hist, char* file_base, int iter)
+{
+    int z;
+    char c;
+
+    // Graph Properties
+    int graph_offset_x = 10;
+    int graph_offset_y = 10;
+    int graph_padding = 20;
+    int graph_bar_height = 100;
+    int graph_bar_width = 5;
+    int graph_bar_spacing = (int)((float)graph_bar_width * (7.0/5.0));
+    plm_long graph_color_levels = 22;
+
+    //  int fixed_bar_height;   // max bar height (pixels)
+    //  int moving_bar_height;
+    plm_long joint_color;
+
+    float fixed_scale;  // pixels per amt
+    float moving_scale;
+    float joint_scale;
+
+    float moving_max_val=0; 
+    float fixed_max_val=0;
+    float joint_max_val=0;
+
+    int fixed_total_width = mi_hist->fixed.bins * graph_bar_spacing;
+    int moving_total_width = mi_hist->moving.bins * graph_bar_spacing;
+
+    int graph_moving_x_pos = graph_offset_x + graph_bar_height + graph_padding;
+    int graph_moving_y_pos = graph_offset_y + fixed_total_width + graph_padding + graph_bar_height;
+
+    int graph_fixed_x_pos = graph_offset_x;
+    int graph_fixed_y_pos = graph_offset_y + fixed_total_width;
+
+    int border_padding = 5;
+    int border_width = moving_total_width + 2*border_padding;
+    int border_height = fixed_total_width + 2*border_padding;
+    int border_x_pos = graph_moving_x_pos - border_padding;
+    int border_y_pos = graph_offset_y - border_padding + (int)((float)graph_bar_width * (2.0/5.0));
+
+    int canvas_width = 2*graph_offset_x + graph_bar_height + moving_total_width + graph_padding;
+    int canvas_height = 2*graph_offset_y + graph_bar_height + fixed_total_width + graph_padding;
+    
+    double *m_hist = mi_hist->m_hist;
+    double *f_hist = mi_hist->f_hist;
+    double *j_hist = mi_hist->j_hist;
+    
+    char filename[20];
+
+    sprintf(filename, "%s_%04i.xpm", file_base, iter);
+
+    // ----------------------------------------------
+    // Find max value for fixed
+    for(plm_long i=0; i<mi_hist->fixed.bins; i++)
+        if (f_hist[i] > fixed_max_val)
+            fixed_max_val = f_hist[i];
+    
+    // Find max value for moving
+    for(plm_long i=0; i<mi_hist->moving.bins; i++)
+        if (m_hist[i] > moving_max_val)
+            moving_max_val = m_hist[i];
+    
+    // Find max value for joint
+    // (Ignoring bin 0)
+    for(plm_long j=0; j<mi_hist->fixed.bins; j++) {
+        for(plm_long i=0; i<mi_hist->moving.bins; i++) {
+            if ( (i > 0) && (j > 1) )
+                if (j_hist[j*mi_hist->moving.bins + i] > joint_max_val)
+                    joint_max_val = j_hist[j*mi_hist->moving.bins + i];
+        }
+    }
+
+
+    // Generate scaling factors
+    fixed_scale = (float)graph_bar_height / fixed_max_val;
+    moving_scale = (float)graph_bar_height / moving_max_val;
+    joint_scale = (float)graph_color_levels / joint_max_val;
+    // ----------------------------------------------
+
+
+    
+    // ----------------------------------------------
+    // Pull out a canvas and brush!
+    Xpm_canvas* xpm = new Xpm_canvas (canvas_width, canvas_height, 1);
+    Xpm_brush* brush = new Xpm_brush;
+    
+    // setup the palette
+    xpm->add_color ('a', 0xFFFFFF);    // white
+    xpm->add_color ('b', 0x000000);    // black
+    xpm->add_color ('z', 0xFFCC00);    // orange
+
+    // generate a nice BLUE->RED gradient
+    c = 'c';
+    z = 0x0000FF;
+    for (plm_long i=0; i<(graph_color_levels+1); i++)
+    {
+        xpm->add_color (c, z);
+
+        z -= 0x00000B;      // BLUE--
+        z += 0x0B0000;      //  RED++
+
+        c = (char)((int)c + 1); // LETTER++
+    }
+
+    // Prime the XPM Canvas
+    xpm->prime ('a');
+    // ----------------------------------------------
+    
+
+    printf("Drawing Histograms... ");
+
+    
+    /* Generate Moving Histogram */
+    brush->set_type (XPM_BOX);
+    brush->set_color ('b');
+    brush->set_pos (graph_moving_x_pos, graph_moving_y_pos);
+    brush->set_width (graph_bar_width);
+    brush->set_height (0);
+
+    int tmp_h;
+    for(plm_long i=0; i<mi_hist->moving.bins; i++)
+    {
+        tmp_h = (int)(m_hist[i] * moving_scale);
+        brush->set_height (tmp_h);
+        brush->set_y (graph_moving_y_pos - tmp_h);
+        xpm->draw (brush);
+        brush->inc_x (graph_bar_spacing);
+    }
+
+    
+    /* Generate Fixed Histogram */
+    brush->set_type (XPM_BOX);
+    brush->set_color ('b');
+    brush->set_pos (graph_fixed_x_pos, graph_fixed_y_pos);
+    brush->set_width (0);
+    brush->set_height (graph_bar_width);
+
+    for (plm_long i=0; i<mi_hist->fixed.bins; i++)
+    {
+        brush->set_width ((int)(f_hist[i] * fixed_scale));
+        xpm->draw (brush);
+        brush->inc_x ((-1)*graph_bar_spacing);
+    }
+
+
+    /* Generate Joint Histogram */
+    brush->set_type (XPM_BOX);
+    brush->set_color ('b');
+    brush->set_pos (graph_moving_x_pos, graph_fixed_y_pos);
+    brush->set_width (graph_bar_width);
+    brush->set_height (graph_bar_width);
+
+    z = 0;
+    for(plm_long j=0; j<mi_hist->fixed.bins; j++) {
+        for(plm_long i=0; i<mi_hist->moving.bins; i++) {
+            joint_color = (size_t)(j_hist[z++] * joint_scale);
+            if (joint_color > 0) {
+                // special handling for bin 0
+                if (joint_color > graph_color_levels) {
+                    //  printf ("Clamp @ P(%i,%i)\n", i, j);
+                    //  brush.color = (char)(graph_color_levels + 99);
+                    brush->set_color ('z');
+                } else {
+                    brush->set_color ((char)(joint_color + 99));
+                }
+            } else {
+                brush->set_color ('a');
+            }
+            xpm->draw (brush);     
+            brush->inc_x (graph_bar_spacing);
+        }
+        // get ready to render new row
+        brush->set_x (graph_moving_x_pos);
+        brush->inc_y ((-1)*graph_bar_spacing);
+    }
+
+    /* Generate Joint Histogram Border */
+    brush->set_type (XPM_BOX); // top
+    brush->set_color ('b');
+    brush->set_pos (border_x_pos, border_y_pos);
+    brush->set_width (border_width);
+    brush->set_height (1);
+    xpm->draw (brush);
+
+    brush->set_width (1); // left
+    brush->set_height (border_height);
+    xpm->draw (brush);
+
+    brush->set_width (border_width); // bottom
+    brush->set_height (1);
+    brush->inc_y (border_height);
+    xpm->draw (brush);
+
+    brush->set_width (1); // right
+    brush->set_height (border_height);
+    brush->set_pos (border_width, border_y_pos);
+    xpm->draw (brush);
+
+    printf("done.\n");
+    
+    // Write to file
+    xpm->write (filename);
+
+    delete xpm;
+    delete brush; 
+}
diff --git a/src/plastimatch/register/joint_histogram.h b/src/plastimatch/register/joint_histogram.h
new file mode 100644
index 0000000..fef904c
--- /dev/null
+++ b/src/plastimatch/register/joint_histogram.h
@@ -0,0 +1,50 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _joint_histogram_h_
+#define _joint_histogram_h_
+
+#include "plmregister_config.h"
+#include <string>
+#include "histogram.h"
+#include "plm_int.h"
+
+class Volume;
+
+class PLMREGISTER_API Joint_histogram {
+public:
+    Joint_histogram ();
+    Joint_histogram (
+        Mi_hist_type type,
+        plm_long fixed_bins,
+        plm_long moving_bins);
+    ~Joint_histogram ();
+public:
+    void initialize (Volume *fixed, Volume *moving);
+    void reset_histograms ();
+    void dump_hist (int it, const std::string& prefix);
+
+    void add_pvi_8 (
+        const Volume *fixed, 
+        const Volume *moving, 
+        int fidx, 
+        int mvf, 
+        float li_1[3],      /* Fraction of interpolant in lower index */
+        float li_2[3]);     /* Fraction of interpolant in upper index */
+
+    float compute_score (int num_vox);
+
+public:
+    Histogram moving;
+    Histogram fixed;
+    Histogram joint;
+    double* m_hist;
+    double* f_hist;
+    double* j_hist;
+protected:
+    void allocate ();
+};
+
+void dump_xpm_hist (Joint_histogram* mi_hist, char* file_base, int iter);
+
+#endif
diff --git a/src/plastimatch/register/landmark_warp.cxx b/src/plastimatch/register/landmark_warp.cxx
index 23942b6..0edc8ef 100644
--- a/src/plastimatch/register/landmark_warp.cxx
+++ b/src/plastimatch/register/landmark_warp.cxx
@@ -129,7 +129,7 @@ landmark_convert_mm_to_voxel (
     plm_long *dim,
     const float *direction_cosines)
 {
-    for (int i = 0; i < landmarks_mm.get_count(); i++) {
+    for (size_t i = 0; i < landmarks_mm.get_count(); i++) {
 	for (int d = 0; d < 3; d++) {
 	    landvox[i*3 + d] = ROUND_INT (
 		( landmarks_mm.point(i,d)
diff --git a/src/plastimatch/register/metric_parms.cxx b/src/plastimatch/register/metric_parms.cxx
new file mode 100644
index 0000000..f56c97c
--- /dev/null
+++ b/src/plastimatch/register/metric_parms.cxx
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmregister_config.h"
+#include <string>
+#include "logfile.h"
+#include "metric_parms.h"
+#include "string_util.h"
+
+Metric_parms::Metric_parms ()
+{
+    metric_type = SIMILARITY_METRIC_MSE;
+    metric_lambda = 1.0;
+}
+
+Plm_return_code
+Metric_parms::set_metric_type (const std::string& val)
+{
+    if (val == "dm" || val == "dmap") {
+        this->metric_type = SIMILARITY_METRIC_DMAP;
+        return PLM_SUCCESS;
+    }
+    else if (val == "gm") {
+        this->metric_type = SIMILARITY_METRIC_GM;
+        return PLM_SUCCESS;
+    }
+    else if (val == "mattes") {
+        this->metric_type = SIMILARITY_METRIC_MI_MATTES;
+        return PLM_SUCCESS;
+    }
+    else if (val == "mse" || val == "MSE") {
+        this->metric_type = SIMILARITY_METRIC_MSE;
+        return PLM_SUCCESS;
+    }
+    else if (val == "mi" || val == "MI") {
+#if PLM_CONFIG_LEGACY_MI_METRIC
+        this->metric_type = SIMILARITY_METRIC_MI_VW;
+#else
+        this->metric_type = SIMILARITY_METRIC_MI_MATTES;
+#endif
+        return PLM_SUCCESS;
+    }
+    else if (val == "mi_vw" || val == "viola-wells") {
+        this->metric_type = SIMILARITY_METRIC_MI_VW;
+        return PLM_SUCCESS;
+    }
+    else if (val == "nmi" || val == "NMI") {
+        this->metric_type = SIMILARITY_METRIC_NMI;
+        return PLM_SUCCESS;
+    }
+    else {
+        return PLM_ERROR;
+    }
+}
diff --git a/src/plastimatch/register/metric_parms.h b/src/plastimatch/register/metric_parms.h
new file mode 100644
index 0000000..fc4aceb
--- /dev/null
+++ b/src/plastimatch/register/metric_parms.h
@@ -0,0 +1,28 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _metric_parms_h_
+#define _metric_parms_h_
+
+#include "plmregister_config.h"
+#include <string>
+#include <vector>
+#include "plm_return_code.h"
+#include "similarity_metric_type.h"
+
+class PLMREGISTER_API Metric_parms {
+public:
+    Metric_parms ();
+public:
+    Similarity_metric_type metric_type;
+    float metric_lambda;
+
+    std::string fixed_fn;
+    std::string moving_fn;
+    std::string fixed_roi_fn;
+    std::string moving_roi_fn;
+public:
+    Plm_return_code set_metric_type (const std::string& val);
+};
+
+#endif
diff --git a/src/plastimatch/register/translation_mse.h b/src/plastimatch/register/metric_state.cxx
similarity index 51%
copy from src/plastimatch/register/translation_mse.h
copy to src/plastimatch/register/metric_state.cxx
index 82a3173..75e6356 100644
--- a/src/plastimatch/register/translation_mse.h
+++ b/src/plastimatch/register/metric_state.cxx
@@ -1,17 +1,19 @@
-/* -----------------------------------------------------------------------
-   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
-   ----------------------------------------------------------------------- */
-#ifndef _translation_mse_h_
-#define _translation_mse_h_
-
-#include "plmregister_config.h"
-#include "volume.h"
-
-float
-translation_mse (
-    const Stage_parms *stage,
-    const Volume::Pointer& fixed,
-    const Volume::Pointer& moving,
-    const float dxyz[3]);
-
-#endif
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmregister_config.h"
+
+#include "joint_histogram.h"
+#include "metric_state.h"
+
+Metric_state::Metric_state ()
+{
+    metric_type = SIMILARITY_METRIC_MSE;
+    metric_lambda = 1.f;
+    mi_hist = 0;
+}
+
+Metric_state::~Metric_state ()
+{
+    delete mi_hist;
+}
diff --git a/src/plastimatch/register/metric_state.h b/src/plastimatch/register/metric_state.h
new file mode 100644
index 0000000..a926a72
--- /dev/null
+++ b/src/plastimatch/register/metric_state.h
@@ -0,0 +1,39 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _metric_state_h_
+#define _metric_state_h_
+
+#include "plmregister_config.h"
+#include "similarity_metric_type.h"
+#include "volume.h"
+
+class Joint_histogram;
+
+class PLMREGISTER_API Metric_state
+{
+public:
+    SMART_POINTER_SUPPORT (Metric_state);
+public:
+    Metric_state ();
+    ~Metric_state ();
+public:
+    Volume::Pointer fixed_ss;
+    Volume::Pointer moving_ss;
+    Volume::Pointer fixed_grad;
+    Volume::Pointer moving_grad;
+    Volume::Pointer fixed_roi;
+    Volume::Pointer moving_roi;
+
+    Similarity_metric_type metric_type;
+    float metric_lambda;
+
+    Joint_histogram *mi_hist;
+
+public:
+    const char *metric_string () {
+        return similarity_metric_type_string (metric_type);
+    }
+};
+
+#endif
diff --git a/src/plastimatch/register/process_parms.cxx b/src/plastimatch/register/process_parms.cxx
index 537ade2..b2e8231 100644
--- a/src/plastimatch/register/process_parms.cxx
+++ b/src/plastimatch/register/process_parms.cxx
@@ -99,16 +99,12 @@ Process_parms::execute_process (Registration_data::Pointer& regd) const
         }
         
         if (adjust_fixed) {
-            regd->fixed_image->set_itk (
-                itk_adjust (
-                    regd->fixed_image->itk_float(),
-                    parms));
+            Plm_image::Pointer& fixed = regd->get_fixed_image();
+            fixed->set_itk (itk_adjust (fixed->itk_float(), parms));
         }
         if (adjust_moving) {
-            regd->moving_image->set_itk (
-                itk_adjust (
-                    regd->moving_image->itk_float(),
-                    parms));
+            Plm_image::Pointer& moving = regd->get_moving_image();
+            moving->set_itk (itk_adjust (moving->itk_float(), parms));
         }
     }
 }
diff --git a/src/plastimatch/register/rbf_gauss.cxx b/src/plastimatch/register/rbf_gauss.cxx
index 2a0920a..38b78bd 100644
--- a/src/plastimatch/register/rbf_gauss.cxx
+++ b/src/plastimatch/register/rbf_gauss.cxx
@@ -402,14 +402,10 @@ bspline_rbf_find_coeffs (
 )
 {
     bspline_rbf_find_coeffs_reg (coeff, lw);
-    //bspline_rbf_find_coeffs_noreg(vector_field, parms);
-
-    int i;
-    for (i=0; i < lw->m_fixed_landmarks.get_count(); i++) {
-	printf("coeff %4d  %.4f %.4f %.4f\n",  i,
-	    coeff[3*i+0],
-	    coeff[3*i+1],
-	    coeff[3*i+2]);
+
+    for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) {
+	printf("coeff %4d  %.4f %.4f %.4f\n",
+            (int) i, coeff[3*i+0], coeff[3*i+1], coeff[3*i+2]);
     }
 
 #if defined (commentout)
@@ -537,7 +533,6 @@ rbf_gauss_update_vf_no_dircos (
     }
 }
 
-
 void
 rbf_gauss_warp (Landmark_warp *lw)
 {
@@ -545,7 +540,6 @@ rbf_gauss_warp (Landmark_warp *lw)
     float origin[3], spacing[3];
     float direction_cosines[9];
     plm_long dim[3];
-    int i;
     Volume::Pointer moving;
     Volume *vf_out, *warped_out;
 
@@ -557,12 +551,13 @@ rbf_gauss_warp (Landmark_warp *lw)
 	rbf_cluster_find_adapt_radius( lw );
     }
     else {
-	for(i = 0; i < lw->m_fixed_landmarks.get_count(); i++) 
+	for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) 
 	    lw->adapt_radius[i]=lw->rbf_radius;
     }
 
-    for (i = 0; i < lw->m_fixed_landmarks.get_count(); i++) 
+    for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) {
 	printf("%f\n", lw->adapt_radius[i]);
+    }
 
     /* Solve for RBF weights */
     coeff = (float*) malloc (
diff --git a/src/plastimatch/register/registration.cxx b/src/plastimatch/register/registration.cxx
index 0bf6744..3865669 100644
--- a/src/plastimatch/register/registration.cxx
+++ b/src/plastimatch/register/registration.cxx
@@ -73,13 +73,13 @@ Registration::~Registration ()
     delete d_ptr;
 }
 
-int
+Plm_return_code
 Registration::set_command_file (const std::string& command_file)
 {
     return d_ptr->rparms->parse_command_file (command_file.c_str());
 }
 
-int
+Plm_return_code
 Registration::set_command_string (const std::string& command_string)
 {
     return d_ptr->rparms->set_command_string (command_string);
@@ -88,25 +88,25 @@ Registration::set_command_string (const std::string& command_string)
 void
 Registration::set_fixed_image (Plm_image::Pointer& fixed)
 {
-    d_ptr->rdata->fixed_image = fixed;
+    d_ptr->rdata->set_fixed_image (fixed);
 }
 
 void
 Registration::set_moving_image (Plm_image::Pointer& moving)
 {
-    d_ptr->rdata->moving_image = moving;
+    d_ptr->rdata->set_moving_image (moving);
 }
 
 void
 Registration::set_fixed_roi (Plm_image::Pointer& fixed_roi)
 {
-    d_ptr->rdata->fixed_roi = fixed_roi;
+    d_ptr->rdata->set_fixed_roi (fixed_roi);
 }
 
 void
 Registration::set_moving_roi (Plm_image::Pointer& moving_roi)
 {
-    d_ptr->rdata->moving_roi = moving_roi;
+    d_ptr->rdata->set_moving_roi (moving_roi);
 }
 
 Registration_data::Pointer
@@ -131,10 +131,11 @@ set_fixed_image_region_global (Registration_data::Pointer& regd)
 {
     int use_magic_value = 1;
 
-    regd->fixed_region_origin = regd->fixed_image->itk_float()->GetOrigin();
-    regd->fixed_region_spacing = regd->fixed_image->itk_float()->GetSpacing();
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    regd->fixed_region_origin = fixed_image->itk_float()->GetOrigin();
+    regd->fixed_region_spacing = fixed_image->itk_float()->GetSpacing();
 
-    if (regd->fixed_roi) {
+    if (regd->get_fixed_roi()) {
         FloatImageType::RegionType::IndexType valid_index;
         FloatImageType::RegionType::SizeType valid_size;
 
@@ -142,8 +143,8 @@ set_fixed_image_region_global (Registration_data::Pointer& regd)
         typedef itk::ImageRegionConstIteratorWithIndex< 
             UCharImageType > IteratorType;
         UCharImageType::RegionType region 
-            = regd->fixed_roi->itk_uchar()->GetLargestPossibleRegion();
-        IteratorType it (regd->fixed_roi->itk_uchar(), region);
+            = regd->get_fixed_roi()->itk_uchar()->GetLargestPossibleRegion();
+        IteratorType it (regd->get_fixed_roi()->itk_uchar(), region);
 
         int first = 1;
         valid_index[0] = 0;
@@ -189,14 +190,15 @@ set_fixed_image_region_global (Registration_data::Pointer& regd)
         valid_size[2] = 1;
 
         /* Make sure the image is ITK float */
-        FloatImageType::Pointer fixed_image = regd->fixed_image->itk_float();
+        Plm_image::Pointer fixed_image = regd->get_fixed_image();
+        FloatImageType::Pointer fixed = fixed_image->itk_float();
 
         /* Search for bounding box of patient */
         typedef itk::ImageRegionConstIteratorWithIndex <
             FloatImageType > IteratorType;
         FloatImageType::RegionType region 
-            = fixed_image->GetLargestPossibleRegion();
-        IteratorType it (fixed_image, region);
+            = fixed->GetLargestPossibleRegion();
+        IteratorType it (fixed, region);
 
         int first = 1;
         for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
@@ -230,7 +232,7 @@ set_fixed_image_region_global (Registration_data::Pointer& regd)
                 valid_size[i]++;
             }
             if (valid_size[i] + valid_index[i] 
-                < fixed_image->GetLargestPossibleRegion().GetSize()[i])
+                < fixed->GetLargestPossibleRegion().GetSize()[i])
             {
                 valid_size[i]++;
             }
@@ -239,7 +241,7 @@ set_fixed_image_region_global (Registration_data::Pointer& regd)
         regd->fixed_region.SetSize(valid_size);
     } else {
         regd->fixed_region 
-            = regd->fixed_image->itk_float()->GetLargestPossibleRegion();
+            = fixed_image->itk_float()->GetLargestPossibleRegion();
     }
 }
 
@@ -258,6 +260,9 @@ save_output (
     const std::string& valid_roi_out_fn
 )
 {
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
+
     /* Handle null xf, make it zero translation */
     if (xf_out->m_type == XFORM_NONE) {
         xf_out->init_trn ();
@@ -269,7 +274,7 @@ save_output (
         logfile_printf ("Writing transformation ...\n");
         if (xf_out_itk && xf_out->m_type == XFORM_GPUIT_BSPLINE) {
             Plm_image_header pih;
-            pih.set_from_plm_image (regd->fixed_image);
+            pih.set_from_plm_image (fixed_image);
             Xform::Pointer xf_tmp = xform_to_itk_bsp (xf_out, &pih, 0);
             xf_tmp->save (*it);
         } else {
@@ -294,10 +299,11 @@ save_output (
             im_warped = Plm_image::New();
         }
         
-        pih.set_from_plm_image (regd->fixed_image);
+        pih.set_from_plm_image (fixed_image);
 
         logfile_printf ("Warping...\n");
-        plm_warp (im_warped, vfp, xf_out, &pih, regd->moving_image, 
+        Plm_image::Pointer moving_image = regd->get_moving_image();
+        plm_warp (im_warped, vfp, xf_out, &pih, moving_image,
             default_value, 0, 1);
 
         if (img_out_fn[0]) {
@@ -325,7 +331,7 @@ save_output (
         if (valid_roi_out_fn[0]) {
             logfile_printf ("Warping valid ROI...\n");
             Plm_image::Pointer valid_roi
-                = Plm_image::clone (regd->moving_image);
+                = Plm_image::clone (moving_image);
 #if defined (commentout)
             plm_warp (im_warped, vfp, xf_out, &pih, regd->moving_image, 
                 default_value, 0, 1);
@@ -336,7 +342,7 @@ save_output (
 
 Xform::Pointer
 Registration::do_registration_stage (
-    Stage_parms* stage            /* Input */
+    Stage_parms* stage
 )
 {
     Registration_data::Pointer regd = d_ptr->rdata;
@@ -384,8 +390,7 @@ Registration::do_registration_stage (
         if (stage->impl_type == IMPLEMENTATION_ITK) {
             xf_out = do_itk_registration_stage (regd.get(), xf_in, stage);
         } else {
-            xf_out = do_gpuit_bspline_stage (regp.get(), regd.get(), 
-                xf_in, stage);
+            xf_out = do_gpuit_bspline_stage (regd.get(), xf_in, stage);
         }
         break;
     case STAGE_TRANSFORM_VECTOR_FIELD:
@@ -418,23 +423,29 @@ set_automatic_parameters (
     Registration_data::Pointer& regd, 
     Registration_parms::Pointer& regp)
 {
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
     std::list<Stage_parms*>& stages = regp->get_stages();
     std::list<Stage_parms*>::iterator it;
     for (it = stages.begin(); it != stages.end(); it++) {
         Stage_parms* sp = *it;
         if (sp->resample_type == RESAMPLE_AUTO) {
             set_auto_resample (
-                sp->resample_rate_fixed, regd->fixed_image.get());
+                sp->resample_rate_fixed, fixed_image.get());
             set_auto_resample (
-                sp->resample_rate_moving, regd->moving_image.get());
+                sp->resample_rate_moving, moving_image.get());
         }
     }
 }
 
 static void
-check_output_resolution (Xform::Pointer& xf_out, Registration_data::Pointer& regd)
+check_output_resolution (
+    Xform::Pointer& xf_out,
+    Registration_data::Pointer& regd)
 {
-    Volume *fixed = regd->fixed_image->get_vol ();
+    Plm_image::Pointer fixed_image = regd->get_fixed_image();
+    Plm_image::Pointer moving_image = regd->get_moving_image();
+    Volume *fixed = fixed_image->get_vol ();
     int ss[3];
     Plm_image_header pih;
     float grid_spacing[3];
diff --git a/src/plastimatch/register/registration.h b/src/plastimatch/register/registration.h
index aca6409..725c330 100644
--- a/src/plastimatch/register/registration.h
+++ b/src/plastimatch/register/registration.h
@@ -19,8 +19,8 @@ public:
     Registration ();
     ~Registration ();
 public:
-    int set_command_file (const std::string& command_file);
-    int set_command_string (const std::string& command_string);
+    Plm_return_code set_command_file (const std::string& command_file);
+    Plm_return_code set_command_string (const std::string& command_string);
     void set_fixed_image (Plm_image::Pointer& fixed);
     void set_moving_image (Plm_image::Pointer& moving);
     void set_fixed_roi (Plm_image::Pointer& fixed_roi);
diff --git a/src/plastimatch/register/registration_data.cxx b/src/plastimatch/register/registration_data.cxx
index d28b14b..2e146b4 100644
--- a/src/plastimatch/register/registration_data.cxx
+++ b/src/plastimatch/register/registration_data.cxx
@@ -3,19 +3,25 @@
    ----------------------------------------------------------------------- */
 #include "plmregister_config.h"
 
+#include "distance_map.h"
 #include "logfile.h"
 #include "plm_image.h"
 #include "plm_image_type.h"
 #include "print_and_exit.h"
 #include "registration_data.h"
 #include "registration_parms.h"
+#include "registration_resample.h"
 #include "shared_parms.h"
 #include "stage_parms.h"
+#include "volume_grad.h"
 
 class Registration_data_private
 {
 public:
     Stage_parms auto_parms;
+    std::map <std::string, Registration_similarity_data::Pointer>
+        similarity_images;
+    std::list<std::string> similarity_indices;
 public:
     Registration_data_private () {
     }
@@ -40,19 +46,6 @@ Registration_data::~Registration_data ()
 void
 Registration_data::load_global_input_files (Registration_parms::Pointer& regp)
 {
-    Plm_image_type image_type = PLM_IMG_TYPE_ITK_FLOAT;
-
-    /* Load images */
-    logfile_printf ("Loading fixed image: %s\n", 
-        regp->get_fixed_fn().c_str());
-    this->fixed_image = Plm_image::New (new Plm_image (
-            regp->get_fixed_fn(), image_type));
-
-    logfile_printf ("Loading moving image: %s\n", 
-        regp->get_moving_fn().c_str());
-    this->moving_image = Plm_image::New (new Plm_image (
-            regp->get_moving_fn(), image_type));
-
     this->load_shared_input_files (regp->get_shared_parms());
 }
 
@@ -65,18 +58,44 @@ Registration_data::load_stage_input_files (const Stage_parms* stage)
 void
 Registration_data::load_shared_input_files (const Shared_parms* shared)
 {
-    /* load "global" rois */
-    if (shared->fixed_roi_fn != "") {
-        logfile_printf ("Loading fixed roi: %s\n", 
-            shared->fixed_roi_fn.c_str());
-        this->fixed_roi = Plm_image::New (
-            shared->fixed_roi_fn, PLM_IMG_TYPE_ITK_UCHAR);
-    }
-    if (shared->moving_roi_fn != "") {
-        logfile_printf ("Loading moving roi: %s\n", 
-            shared->moving_roi_fn.c_str());
-        this->moving_roi = Plm_image::New (
-            shared->moving_roi_fn, PLM_IMG_TYPE_ITK_UCHAR);
+    std::map<std::string,Metric_parms>::const_iterator metric_it;
+    for (metric_it = shared->metric.begin();
+         metric_it != shared->metric.end(); ++metric_it)
+    {
+        const std::string& index = metric_it->first;
+        const Metric_parms& mp = metric_it->second;
+
+        /* Sanity check -- there should be at least a fixed and moving */
+        if (mp.fixed_fn == "") {
+            continue;
+        }
+        if (mp.moving_fn == "") {
+            continue;
+        }
+        
+        /* Load images */
+        logfile_printf ("Loading fixed image [%s]: %s\n", 
+            index.c_str(), mp.fixed_fn.c_str());
+        this->set_fixed_image (index,
+            Plm_image::New (mp.fixed_fn, PLM_IMG_TYPE_ITK_FLOAT));
+        logfile_printf ("Loading moving image [%s]: %s\n", 
+            index.c_str(), mp.moving_fn.c_str());
+        this->set_moving_image (index,
+            Plm_image::New (mp.moving_fn, PLM_IMG_TYPE_ITK_FLOAT));
+        
+        /* Load rois */
+        if (mp.fixed_roi_fn != "") {
+            logfile_printf ("Loading fixed roi [%s]: %s\n", 
+                index.c_str(), mp.fixed_roi_fn.c_str());
+            this->set_fixed_roi (index,
+                Plm_image::New (mp.fixed_roi_fn, PLM_IMG_TYPE_ITK_UCHAR));
+        }
+        if (mp.moving_roi_fn != "") {
+            logfile_printf ("Loading moving roi [%s]: %s\n", 
+                index.c_str(), mp.moving_roi_fn.c_str());
+            this->set_moving_roi (index,
+                Plm_image::New (mp.moving_roi_fn, PLM_IMG_TYPE_ITK_UCHAR));
+        }
     }
 
     /* load stiffness */
@@ -119,8 +138,221 @@ Registration_data::load_shared_input_files (const Shared_parms* shared)
     }
 }
 
+Registration_similarity_data::Pointer&
+Registration_data::get_similarity_images (
+    std::string index)
+{
+    if (index == "") {
+        index = DEFAULT_IMAGE_KEY;
+    }
+    if (!d_ptr->similarity_images[index]) {
+        d_ptr->similarity_images[index] = Registration_similarity_data::New();
+    }
+    return d_ptr->similarity_images[index];
+}
+
+void
+Registration_data::set_fixed_image (const Plm_image::Pointer& image)
+{
+    this->set_fixed_image (DEFAULT_IMAGE_KEY, image);
+}
+
+void
+Registration_data::set_fixed_image (
+    const std::string& index,
+    const Plm_image::Pointer& image)
+{
+    this->get_similarity_images(index)->fixed = image;
+}
+
+void
+Registration_data::set_moving_image (const Plm_image::Pointer& image)
+{
+    this->set_moving_image (DEFAULT_IMAGE_KEY, image);
+}
+
+void
+Registration_data::set_moving_image (
+    const std::string& index,
+    const Plm_image::Pointer& image)
+{
+    this->get_similarity_images(index)->moving = image;
+}
+
+void
+Registration_data::set_fixed_roi (const Plm_image::Pointer& image)
+{
+    this->set_fixed_roi (DEFAULT_IMAGE_KEY, image);
+}
+
+void
+Registration_data::set_fixed_roi (
+    const std::string& index,
+    const Plm_image::Pointer& image)
+{
+    this->get_similarity_images(index)->fixed_roi = image;
+}
+
+void
+Registration_data::set_moving_roi (const Plm_image::Pointer& image)
+{
+    this->set_moving_roi (DEFAULT_IMAGE_KEY, image);
+}
+
+void
+Registration_data::set_moving_roi (
+    const std::string& index,
+    const Plm_image::Pointer& image)
+{
+    this->get_similarity_images(index)->moving_roi = image;
+}
+
+Plm_image::Pointer&
+Registration_data::get_fixed_image ()
+{
+    return this->get_fixed_image(DEFAULT_IMAGE_KEY);
+}
+
+Plm_image::Pointer&
+Registration_data::get_fixed_image (
+    const std::string& index)
+{
+    return this->get_similarity_images(index)->fixed;
+}
+
+Plm_image::Pointer&
+Registration_data::get_moving_image ()
+{
+    return this->get_moving_image(DEFAULT_IMAGE_KEY);
+}
+
+Plm_image::Pointer&
+Registration_data::get_moving_image (
+    const std::string& index)
+{
+    return this->get_similarity_images(index)->moving;
+}
+
+Plm_image::Pointer&
+Registration_data::get_fixed_roi ()
+{
+    return this->get_fixed_roi(DEFAULT_IMAGE_KEY);
+}
+
+Plm_image::Pointer&
+Registration_data::get_fixed_roi (
+    const std::string& index)
+{
+    return this->get_similarity_images(index)->fixed_roi;
+}
+
+Plm_image::Pointer&
+Registration_data::get_moving_roi ()
+{
+    return this->get_moving_roi(DEFAULT_IMAGE_KEY);
+}
+
+Plm_image::Pointer&
+Registration_data::get_moving_roi (
+    const std::string& index)
+{
+    return this->get_similarity_images(index)->moving_roi;
+}
+
+const std::list<std::string>&
+Registration_data::get_similarity_indices ()
+{
+    d_ptr->similarity_indices.clear ();
+    
+    std::map<std::string,
+        Registration_similarity_data::Pointer>::const_iterator it;
+    for (it = d_ptr->similarity_images.begin();
+         it != d_ptr->similarity_images.end(); ++it)
+    {
+        if (it->second->fixed && it->second->moving) {
+            if (it->first == DEFAULT_IMAGE_KEY) {
+                d_ptr->similarity_indices.push_front (it->first);
+            } else {
+                d_ptr->similarity_indices.push_back (it->first);
+            }
+        }
+    }
+    return d_ptr->similarity_indices;
+}
+
 Stage_parms*
 Registration_data::get_auto_parms ()
 {
     return &d_ptr->auto_parms;
 }
+
+static Volume::Pointer
+make_dmap (const Volume::Pointer& image)
+{
+    Plm_image::Pointer pi = Plm_image::New (image);
+    Distance_map dm;
+
+    dm.set_input_image (pi);
+    dm.run ();
+
+    Plm_image im_out (dm.get_output_image());
+    return im_out.get_volume_float ();
+}
+
+void populate_similarity_list (
+    std::list<Metric_state::Pointer>& similarity_data,
+    Registration_data *regd,
+    const Stage_parms *stage
+)
+{
+    const Shared_parms *shared = stage->get_shared_parms();
+
+    /* Clear out the list */
+    similarity_data.clear ();
+
+    const std::list<std::string>& similarity_indices
+        = regd->get_similarity_indices ();
+    std::list<std::string>::const_iterator ind_it;
+    for (ind_it = similarity_indices.begin();
+         ind_it != similarity_indices.end(); ++ind_it)
+    {
+        Plm_image::Pointer fixed_image = regd->get_fixed_image (*ind_it);
+        Plm_image::Pointer moving_image = regd->get_moving_image (*ind_it);
+        Volume::Pointer& fixed = fixed_image->get_volume_float ();
+        Volume::Pointer& moving = moving_image->get_volume_float ();
+
+        Metric_state::Pointer ssi = Metric_state::New();
+
+        /* Subsample images */
+        ssi->fixed_ss = registration_resample_volume (
+            fixed, stage, stage->resample_rate_fixed);
+        ssi->moving_ss = registration_resample_volume (
+            moving, stage, stage->resample_rate_moving);
+
+        /* Metric */
+        const Metric_parms& metric_parms = shared->metric.find(*ind_it)->second;
+        ssi->metric_type = metric_parms.metric_type;
+        if (ssi->metric_type == SIMILARITY_METRIC_MI_VW) {
+            ssi->metric_type = SIMILARITY_METRIC_MI_MATTES;
+        }
+        ssi->metric_lambda = metric_parms.metric_lambda;
+
+        /* Gradient magnitude is MSE on gradient image */
+        if (ssi->metric_type == SIMILARITY_METRIC_GM) {
+            ssi->fixed_ss = volume_gradient_magnitude (ssi->fixed_ss);
+            ssi->moving_ss = volume_gradient_magnitude (ssi->moving_ss);
+        }
+
+        /* Distance map is MSE on distance map images */
+        if (ssi->metric_type == SIMILARITY_METRIC_DMAP) {
+            ssi->fixed_ss = make_dmap (ssi->fixed_ss);
+            ssi->moving_ss = make_dmap (ssi->moving_ss);
+        }
+
+        /* Make spatial gradient image */
+        ssi->moving_grad = volume_gradient (ssi->moving_ss);
+
+        /* Append to list */
+        similarity_data.push_back (ssi);
+    }
+}
diff --git a/src/plastimatch/register/registration_data.h b/src/plastimatch/register/registration_data.h
index 9b3ee89..491c2a0 100644
--- a/src/plastimatch/register/registration_data.h
+++ b/src/plastimatch/register/registration_data.h
@@ -6,9 +6,11 @@
 
 #include "plmregister_config.h"
 #include "itk_image_type.h"
+#include "metric_state.h"
 #include "plm_image.h"
 #include "pointset.h"
 #include "registration_parms.h"
+#include "registration_similarity_data.h"
 #include "smart_pointer.h"
 
 class Plm_image;
@@ -16,16 +18,21 @@ class Registration_data_private;
 class Shared_parms;
 class Stage_parms;
 
+/*! \brief 
+ * The Registration_data class holds global data shared across multiple 
+ * registration stages.  These data include images, landmarks, 
+ * ROIs, and automatic parameters.
+ */
 class PLMREGISTER_API Registration_data {
 public:
     SMART_POINTER_SUPPORT (Registration_data);
     Registration_data_private *d_ptr;
 public:
-    /* Input images */
-    Plm_image::Pointer fixed_image;
-    Plm_image::Pointer moving_image;
-    Plm_image::Pointer fixed_roi;
-    Plm_image::Pointer moving_roi;
+    Registration_data ();
+    ~Registration_data ();
+
+public:
+    /* Regularization stiffness image */
     Plm_image::Pointer fixed_stiffness;
 
     /* Input landmarks */
@@ -38,13 +45,47 @@ public:
     FloatImageType::SpacingType fixed_region_spacing;
 
 public:
-    Registration_data ();
-    ~Registration_data ();
     void load_global_input_files (Registration_parms::Pointer& regp);
     void load_stage_input_files (const Stage_parms* regp);
     void load_shared_input_files (const Shared_parms* shared);
 
+    Registration_similarity_data::Pointer&
+        get_similarity_images (std::string index);
+
+    void set_fixed_image (const Plm_image::Pointer& image);
+    void set_fixed_image (const std::string& index,
+        const Plm_image::Pointer& image);
+    void set_moving_image (const Plm_image::Pointer& image);
+    void set_moving_image (const std::string& index,
+        const Plm_image::Pointer& image);
+    void set_fixed_roi (const Plm_image::Pointer& image);
+    void set_fixed_roi (const std::string& index,
+        const Plm_image::Pointer& image);
+    void set_moving_roi (const Plm_image::Pointer& image);
+    void set_moving_roi (const std::string& index,
+        const Plm_image::Pointer& image);
+    Plm_image::Pointer& get_fixed_image ();
+    Plm_image::Pointer& get_fixed_image (const std::string& index);
+    Plm_image::Pointer& get_moving_image ();
+    Plm_image::Pointer& get_moving_image (const std::string& index);
+    Plm_image::Pointer& get_fixed_roi ();
+    Plm_image::Pointer& get_fixed_roi (const std::string& index);
+    Plm_image::Pointer& get_moving_roi ();
+    Plm_image::Pointer& get_moving_roi (const std::string& index);
+
+    /*! \brief Get list of indices which have both a fixed and moving image.
+      The default image (index "0") will be the first index in the list.  
+      The remaining indices will be sorted in order they appear 
+      in the command file. */
+    const std::list<std::string>& get_similarity_indices ();
+    
     Stage_parms* get_auto_parms ();
 };
 
+void populate_similarity_list (
+    std::list<Metric_state::Pointer>& similarity_data,
+    Registration_data *regd,
+    const Stage_parms *stage
+);
+
 #endif
diff --git a/src/plastimatch/register/registration_metric_type.h b/src/plastimatch/register/registration_metric_type.h
deleted file mode 100755
index 90ae189..0000000
--- a/src/plastimatch/register/registration_metric_type.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -----------------------------------------------------------------------
-   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
-   ----------------------------------------------------------------------- */
-#ifndef _registration_metric_type_h_
-#define _registration_metric_type_h_
-
-enum Registration_metric_type {
-    REGISTRATION_METRIC_NONE,
-    REGISTRATION_METRIC_GM,
-    REGISTRATION_METRIC_MI_MATTES,
-    REGISTRATION_METRIC_MI_VW,
-    REGISTRATION_METRIC_MSE,
-    REGISTRATION_METRIC_NMI
-};
-
-const char* registration_metric_type_string (Registration_metric_type);
-
-#endif
diff --git a/src/plastimatch/register/registration_parms.cxx b/src/plastimatch/register/registration_parms.cxx
index 62b974b..df210ef 100644
--- a/src/plastimatch/register/registration_parms.cxx
+++ b/src/plastimatch/register/registration_parms.cxx
@@ -10,13 +10,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#if defined (_WIN32)
-// win32 directory stuff
-#else
-#include <sys/types.h>
-#include <dirent.h>
-#endif
 
+#include "groupwise_parms.h"
 #include "logfile.h"
 #include "parameter_parser.h"
 #include "plm_return_code.h"
@@ -28,22 +23,19 @@
 class Registration_parms_private
 {
 public:
-    std::string moving_fn;
-    std::string fixed_fn;
     std::list<Stage_parms*> stages;
     Shared_parms *shared;
-
-    /* GCS FIX: These were disabled, and are needing some re-engineering */
-    std::list< std::string > moving_jobs;
-    std::list< std::string > fixed_jobs;
+    Groupwise_parms *gw_parms;
 
 public:
     Registration_parms_private () {
         shared = new Shared_parms;
+        gw_parms = 0;
     }
     ~Registration_parms_private () {
         delete_all_stages ();
         delete shared;
+        delete gw_parms;
     }
     void delete_all_stages () {
         std::list<Stage_parms*>::iterator it;
@@ -62,6 +54,8 @@ public:
     Registration_parms_parser (Registration_parms *rp)
     {
         this->rp = rp;
+        this->enable_key_regularization (true);
+        this->set_default_index (DEFAULT_IMAGE_KEY);
     }
 public:
     virtual Plm_return_code begin_section (
@@ -94,9 +88,10 @@ public:
     virtual Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key, 
+        const std::string& index, 
         const std::string& val)
     {
-        return this->rp->set_key_value (section, key, val);
+        return this->rp->set_key_value (section, key, index, val);
     }
 };
 
@@ -110,8 +105,6 @@ Registration_parms::Registration_parms()
     init_type = STAGE_TRANSFORM_NONE;
     default_value = 0.0;
     num_stages = 0;
-    job_idx = 0;
-    num_jobs = 1;
 }
 
 Registration_parms::~Registration_parms()
@@ -119,35 +112,11 @@ Registration_parms::~Registration_parms()
     delete d_ptr;
 }
 
-#if defined (GCS_FIXME)  // Delete this, replace with compose_filename
-// JAS 2012.02.13 -- TODO: Move somewhere more appropriate
-static void
-check_trailing_slash (char* s)
-{
-    int i=0;
-    while (s[i++] != '\0');
-
-    if (s[i-2] != '/') {
-        strcat (s, "/");
-    }
-}
-#endif
-
-
-#if defined (GCS_FIXME)  // Delete this, replace with Dir_list
-int
-populate_jobs ()
-{
-    /* This function should read through the directory, 
-       and identify the input files for each registration role 
-       (fixed, moving, etc.) */
-}
-#endif
-
 Plm_return_code
 Registration_parms::set_key_value (
     const std::string& section,
-    const std::string& key, 
+    const std::string& key,
+    const std::string& index,
     const std::string& val)
 {
     int rc;
@@ -178,39 +147,7 @@ Registration_parms::set_key_value (
     }
 
     /* The following keywords are only allowed globally */
-    if (key == "fixed") {
-        if (!section_global) goto key_only_allowed_in_section_global;
-        d_ptr->fixed_fn = val;
-    }
-    else if (key == "moving") {
-        if (!section_global) goto key_only_allowed_in_section_global;
-        d_ptr->moving_fn = val;
-    }
-#if defined (GCS_FIXME) // stubbed out until above is fixed
-    else if (key == "fixed_dir") {
-        if (!section_global) goto key_only_allowed_in_section_global;
-        this->fixed_dir = val;
-        check_trailing_slash (this->fixed_dir);
-        this->num_jobs = populate_jobs (this->fixed_jobs, this->fixed_dir);
-    }
-    else if (key == "moving_dir") {
-        if (!section_global) goto key_only_allowed_in_section_global;
-        this->moving_dir = val;
-        check_trailing_slash (this->moving_dir);
-        this->num_jobs = populate_jobs (this->moving_jobs, this->moving_dir);
-    }
-    else if (key == "img_out_dir") {
-        if (!section_global) goto key_only_allowed_in_section_global;
-        this->img_out_dir = val;
-        check_trailing_slash (this->img_out_dir);
-    }
-    else if (key == "vf_out_dir") {
-        if (!section_global) goto key_only_allowed_in_section_global;
-        this->vf_out_dir = val;
-        check_trailing_slash (this->vf_out_dir);
-    }
-#endif
-    else if (key == "xf_in"
+    if (key == "xf_in"
         || key == "xform_in"
         || key == "vf_in")
     {
@@ -221,8 +158,20 @@ Registration_parms::set_key_value (
         if (!section_global) goto key_only_allowed_in_section_global;
         this->log_fn = val;
     }
+    else if (key == "group_dir") {
+        if (!section_global) goto key_only_allowed_in_section_global;
+        this->group_dir = val;
+    }
 
     /* The following keywords are allowed either globally or in stages */
+    else if (key == "fixed") {
+        if (section_process) goto key_not_allowed_in_section_process;
+        shared->metric[index].fixed_fn = val;
+    }
+    else if (key == "moving") {
+        if (section_process) goto key_not_allowed_in_section_process;
+        shared->metric[index].moving_fn = val;
+    }
     else if (key == "background_val"
         || key == "default_value")
     {
@@ -240,11 +189,11 @@ Registration_parms::set_key_value (
     }
     else if (key == "fixed_mask" || key == "fixed_roi") {
         if (section_process) goto key_not_allowed_in_section_process;
-        shared->fixed_roi_fn = val;
+        shared->metric[index].fixed_roi_fn = val;
     }
     else if (key == "moving_mask" || key == "moving_roi") {
         if (section_process) goto key_not_allowed_in_section_process;
-        shared->moving_roi_fn = val;
+        shared->metric[index].moving_roi_fn = val;
     }
     else if (key == "fixed_roi_enable") {
         if (section_process) goto key_not_allowed_in_section_process;
@@ -531,47 +480,17 @@ Registration_parms::set_key_value (
     }
     else if (key == "metric" || key == "smetric") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
-        std::vector<std::string> metric_vec = string_split (val, ',');
-        if (metric_vec.size() == 0) {
-            goto error_exit;
-        }
-        stage->metric_type.clear();
-        for (int i = 0; i < metric_vec.size(); i++) {
-            if (metric_vec[i] == "gm") {
-                stage->metric_type.push_back (REGISTRATION_METRIC_GM);
-            }
-            else if (metric_vec[i] == "mattes") {
-                stage->metric_type.push_back (REGISTRATION_METRIC_MI_MATTES);
-            }
-            else if (metric_vec[i] == "mse" || metric_vec[i] == "MSE") {
-                stage->metric_type.push_back (REGISTRATION_METRIC_MSE);
-            }
-            else if (metric_vec[i] == "mi" || metric_vec[i] == "MI") {
-#if PLM_CONFIG_LEGACY_MI_METRIC
-                stage->metric_type.push_back (REGISTRATION_METRIC_MI_VW);
-#else
-                stage->metric_type.push_back (REGISTRATION_METRIC_MI_MATTES);
-#endif
-            }
-            else if (metric_vec[i] == "mi_vw"
-                    || metric_vec[i] == "viola-wells")
-            {
-                stage->metric_type.push_back (REGISTRATION_METRIC_MI_VW);
-            }
-            else if (metric_vec[i] == "nmi" || metric_vec[i] == "NMI") {
-                stage->metric_type.push_back (REGISTRATION_METRIC_NMI);
-            }
-            else {
-                goto error_exit;
-            }
+        if (shared->metric[index].set_metric_type (val) != PLM_SUCCESS) {
+            goto error_exit;
         }
     }
     else if (key == "metric_lambda" || key == "smetric_lambda") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
-        stage->metric_lambda = parse_float_string (val);
-        if (stage->metric_lambda.size() == 0) {
+        float f;
+        if (sscanf (val.c_str(), "%f", &f) != 1) {
             goto error_exit;
         }
+        shared->metric[index].metric_lambda = f;
     }
     else if (key == "histogram_type") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
@@ -741,28 +660,28 @@ Registration_parms::set_key_value (
         }
     }
     else if (key == "mattes_fixed_minVal"
-        ||key == "mi_fixed_minVal") {
+        || key == "mi_fixed_minVal") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
         if (sscanf (val.c_str(), "%g", &stage->mi_fixed_image_minVal) != 1) {
             goto error_exit;
         }
     }
     else if (key == "mattes_fixed_maxVal"
-        ||key == "mi_fixed_maxVal") {
+        || key == "mi_fixed_maxVal") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
         if (sscanf (val.c_str(), "%g", &stage->mi_fixed_image_maxVal) != 1) {
             goto error_exit;
         }
     }
     else if (key == "mattes_moving_minVal"
-        ||key == "mi_moving_minVal") {
+        || key == "mi_moving_minVal") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
         if (sscanf (val.c_str(), "%g", &stage->mi_moving_image_minVal) != 1) {
             goto error_exit;
         }
     }
     else if (key == "mattes_moving_maxVal"
-        ||key == "mi_moving_maxVal") {
+        || key == "mi_moving_maxVal") {
         if (!section_stage) goto key_only_allowed_in_section_stage;
         if (sscanf (val.c_str(), "%g", &stage->mi_moving_image_maxVal) != 1) {
             goto error_exit;
@@ -1083,7 +1002,7 @@ error_exit:
     return PLM_ERROR;
 }
 
-int
+Plm_return_code
 Registration_parms::set_command_string (
     const std::string& command_string
 )
@@ -1093,7 +1012,7 @@ Registration_parms::set_command_string (
     return rpp.parse_config_string (command_string);
 }
 
-int
+Plm_return_code
 Registration_parms::parse_command_file (const char* options_fn)
 {
     /* Read file into string */
@@ -1105,83 +1024,6 @@ Registration_parms::parse_command_file (const char* options_fn)
     return this->set_command_string (buffer.str());
 }
 
-#if defined (GCS_FIX)  // Needs re-engineering
-/* JAS 2012.03.13
- *  This is a temp solution */
-/* GCS 2012-12-28: Nb. regp->job_idx must be set prior to calling 
-   this function */
-void
-Registration_parms::set_job_paths (void)
-{
-    /* Setup input paths */
-    if (*(this->fixed_dir)) {
-        d_ptr->fixed_fn = string_format (
-            "%s%s", this->fixed_dir, this->fixed_jobs[this->job_idx]);
-    }
-    if (*(this->moving_dir)) {
-        d_ptr->moving_fn = string_format (
-            "%s%s", this->moving_dir, this->moving_jobs[this->job_idx]);
-    }
-
-    /* Setup output paths */
-    /*   NOTE: For now, output files inherit moving image names */
-    if (*(this->img_out_dir)) {
-        if (!strcmp (this->img_out_dir, this->moving_dir)) {
-            strcpy (this->img_out_fn, this->img_out_dir);
-            strcat (this->img_out_fn, "warp/");
-            strcat (this->img_out_fn, this->moving_jobs[this->job_idx]);
-        } else {
-            strcpy (this->img_out_fn, this->img_out_dir);
-            strcat (this->img_out_fn, this->moving_jobs[this->job_idx]);
-        }
-        /* If not dicom, we give a default name */
-        if (this->img_out_fmt != IMG_OUT_FMT_DICOM) {
-            std::string fn = string_format ("%s.mha", this->img_out_fn);
-            strcpy (this->img_out_fn, fn.c_str());
-        }
-    } else {
-        /* Output directory not specifed but img_out was... smart fallback*/
-        if (*(this->img_out_fn)) {
-            strcpy (this->img_out_fn, this->moving_dir);
-            strcat (this->img_out_fn, "warp/");
-            strcat (this->img_out_fn, this->moving_jobs[this->job_idx]);
-        }
-    }
-    if (*(this->vf_out_dir)) {
-        if (!strcmp (this->vf_out_dir, this->moving_dir)) {
-            strcpy (this->vf_out_fn, this->img_out_dir);
-            strcat (this->vf_out_fn, "vf/");
-            strcat (this->vf_out_fn, this->moving_jobs[this->job_idx]);
-        } else {
-            strcpy (this->vf_out_fn, this->vf_out_dir);
-            strcat (this->vf_out_fn, this->moving_jobs[this->job_idx]);
-        }
-        /* Give a default name */
-        std::string fn = string_format ("%s_vf.mha", this->vf_out_fn);
-        strcpy (this->vf_out_fn, fn.c_str());
-    } else {
-        /* Output directory not specifed but vf_out was... smart fallback*/
-        if (*(this->vf_out_fn)) {
-            strcpy (this->vf_out_fn, this->moving_dir);
-            strcat (this->vf_out_fn, "vf/");
-            strcat (this->vf_out_fn, this->moving_jobs[this->job_idx]);
-        }
-    }
-}
-#endif
-
-const std::string& 
-Registration_parms::get_fixed_fn ()
-{
-    return d_ptr->fixed_fn;
-}
-
-const std::string& 
-Registration_parms::get_moving_fn ()
-{
-    return d_ptr->moving_fn;
-}
-
 Shared_parms*
 Registration_parms::get_shared_parms ()
 {
diff --git a/src/plastimatch/register/registration_parms.h b/src/plastimatch/register/registration_parms.h
index 28e2d03..1438944 100644
--- a/src/plastimatch/register/registration_parms.h
+++ b/src/plastimatch/register/registration_parms.h
@@ -15,11 +15,14 @@
 #include "smart_pointer.h"
 #include "threading.h"
 
+class Groupwise_parms;
 class Plm_image;
 class Registration_parms_private;
 class Shared_parms;
 class Stage_parms;
 
+#define DEFAULT_IMAGE_KEY "0"
+
 class PLMREGISTER_API Registration_parms {
 public:
     SMART_POINTER_SUPPORT (Registration_parms);
@@ -43,28 +46,29 @@ public:
     std::string fixed_dir;
     std::string img_out_dir;
     std::string vf_out_dir;
-    int job_idx;
-    int num_jobs;
+
+    /* for groupwise registration */
+    std::string group_dir;
 
 public:
     Registration_parms();
     ~Registration_parms();
 public:
-    int set_command_string (const std::string& command_string);
+    Plm_return_code set_command_string (const std::string& command_string);
     Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key, 
+        const std::string& index, 
         const std::string& val);
-    int parse_command_file (const char* options_fn);
+    Plm_return_code parse_command_file (const char* options_fn);
     void set_job_paths (void);
 public:
-    const std::string& get_fixed_fn ();
-    const std::string& get_moving_fn ();
     Shared_parms* get_shared_parms ();
     void delete_all_stages ();
     std::list<Stage_parms*>& get_stages ();
     Stage_parms* append_stage ();
     Stage_parms* append_process_stage ();
+    Groupwise_parms* get_groupwise_parms ();
 };
 
 #endif
diff --git a/src/plastimatch/register/registration_resample.cxx b/src/plastimatch/register/registration_resample.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/register/registration_resample.h b/src/plastimatch/register/registration_resample.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/register/registration_similarity_data.h b/src/plastimatch/register/registration_similarity_data.h
new file mode 100644
index 0000000..c3fae72
--- /dev/null
+++ b/src/plastimatch/register/registration_similarity_data.h
@@ -0,0 +1,24 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _registration_similarity_data_h_
+#define _registration_similarity_data_h_
+
+#include "plmregister_config.h"
+
+/*! \brief 
+ * The Registration_similarity_data class holds original or processed 
+ * images used for similarity measure calculations over multiple stages.
+ */
+class PLMREGISTER_API Registration_similarity_data
+{
+public:
+    SMART_POINTER_SUPPORT (Registration_similarity_data);
+public:
+    Plm_image::Pointer fixed;
+    Plm_image::Pointer moving;
+    Plm_image::Pointer fixed_roi;
+    Plm_image::Pointer moving_roi;
+};
+
+#endif
diff --git a/src/plastimatch/register/registration_util.cxx b/src/plastimatch/register/registration_util.cxx
new file mode 100644
index 0000000..57685da
--- /dev/null
+++ b/src/plastimatch/register/registration_util.cxx
@@ -0,0 +1,44 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmregister_config.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+
+#include "registration_util.h"
+#include "shared_parms.h"
+
+plm_long
+count_fixed_voxels (
+    Registration_data *regd,
+    Stage_parms* stage, 
+    FloatImageType::Pointer& fixed_ss)
+{
+    // Do simple calculation if there is no ROI
+    const Shared_parms *shared = stage->get_shared_parms();
+    if (!shared->fixed_roi_enable || !regd->get_fixed_roi()) {
+        plm_long dim[3];
+        get_image_header (dim, 0, 0, fixed_ss);
+        return dim[0] * dim[1] * dim[2];
+    }
+
+    // Else, iterate through image to find voxels where ROI not zero
+    Plm_image::Pointer& fixed_roi = regd->get_fixed_roi ();
+    const UCharImageType::Pointer itk_fixed_roi = fixed_roi->itk_uchar ();
+    typedef itk::ImageRegionConstIteratorWithIndex < FloatImageType 
+        > IteratorType;
+    FloatImageType::RegionType region = fixed_ss->GetLargestPossibleRegion();
+    IteratorType it (fixed_ss, region);
+    plm_long num_voxels = 0;
+    for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
+        FloatImageType::PointType phys_loc;
+        fixed_ss->TransformIndexToPhysicalPoint (it.GetIndex(), phys_loc);
+        UCharImageType::IndexType roi_idx;
+        bool is_inside = itk_fixed_roi->TransformPhysicalPointToIndex (
+            phys_loc, roi_idx);
+        if (is_inside && itk_fixed_roi->GetPixel (roi_idx)) {
+            num_voxels ++;
+        }
+    }
+    return num_voxels;
+}
+
diff --git a/src/plastimatch/register/registration_resample.h b/src/plastimatch/register/registration_util.h
old mode 100755
new mode 100644
similarity index 55%
copy from src/plastimatch/register/registration_resample.h
copy to src/plastimatch/register/registration_util.h
index 111ffd2..3ad90bb
--- a/src/plastimatch/register/registration_resample.h
+++ b/src/plastimatch/register/registration_util.h
@@ -1,18 +1,17 @@
 /* -----------------------------------------------------------------------
    See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
    ----------------------------------------------------------------------- */
-#ifndef _registration_resample_h_
-#define _registration_resample_h_
+#ifndef _registration_util_h_
+#define _registration_util_h_
 
 #include "plmregister_config.h"
+#include "itk_image_type.h"
+#include "registration_data.h"
 #include "stage_parms.h"
-#include "volume.h"
 
-Volume::Pointer
-registration_resample_volume (
-    const Volume::Pointer& vol,
-    const Stage_parms* stage,
-    const float resample_rate[3]
-);
+plm_long
+count_fixed_voxels (Registration_data *regd,
+    Stage_parms* stage, 
+    FloatImageType::Pointer& fixed_ss);
 
 #endif
diff --git a/src/plastimatch/register/shared_parms.cxx b/src/plastimatch/register/shared_parms.cxx
old mode 100755
new mode 100644
index f861358..947bb8e
--- a/src/plastimatch/register/shared_parms.cxx
+++ b/src/plastimatch/register/shared_parms.cxx
@@ -3,10 +3,13 @@
    ----------------------------------------------------------------------- */
 #include "plmregister_config.h"
 
+#include "logfile.h"
+#include "registration_parms.h"
 #include "shared_parms.h"
 
 Shared_parms::Shared_parms ()
 {
+    this->metric[DEFAULT_IMAGE_KEY] = Metric_parms ();
     this->fixed_roi_enable = true;
     this->moving_roi_enable = true;
     this->fixed_stiffness_enable = true;
@@ -18,6 +21,7 @@ Shared_parms::Shared_parms ()
 
 Shared_parms::Shared_parms (const Shared_parms& s)
 {
+    this->metric = s.metric;
     this->fixed_roi_enable = s.fixed_roi_enable;
     this->moving_roi_enable = s.moving_roi_enable;
     this->fixed_stiffness_enable = s.fixed_stiffness_enable;
@@ -33,9 +37,22 @@ Shared_parms::~Shared_parms ()
 void
 Shared_parms::copy (const Shared_parms *s)
 {
+    this->metric = s->metric;
     this->fixed_roi_enable = s->fixed_roi_enable;
     this->moving_roi_enable = s->moving_roi_enable;
+    this->fixed_stiffness_enable = s->fixed_stiffness_enable;
     this->legacy_subsampling = s->legacy_subsampling;
 
     /* filenames do not propagate when copied */
 }
+
+void
+Shared_parms::log ()
+{
+    lprintf ("LOG Shared parms\n");
+    std::map<std::string, Metric_parms>::iterator it;
+    for (it = this->metric.begin(); it != this->metric.end(); ++it) {
+        lprintf ("Shared metric | %s | %d\n", it->first.c_str(), 
+            it->second.metric_type);
+    }
+}
diff --git a/src/plastimatch/register/shared_parms.h b/src/plastimatch/register/shared_parms.h
old mode 100755
new mode 100644
index b6a2d31..711c14a
--- a/src/plastimatch/register/shared_parms.h
+++ b/src/plastimatch/register/shared_parms.h
@@ -5,7 +5,9 @@
 #define _shared_parms_h_
 
 #include "plmregister_config.h"
+#include <map>
 #include <string>
+#include "metric_parms.h"
 
 class PLMREGISTER_API Shared_parms {
 public:
@@ -14,11 +16,12 @@ public:
     ~Shared_parms ();
 
 public:
+    /* Similarity parms */
+    std::map<std::string, Metric_parms> metric;
+    
     /* ROI */
     bool fixed_roi_enable;
     bool moving_roi_enable;
-    std::string fixed_roi_fn;
-    std::string moving_roi_fn;
     std::string valid_roi_out_fn;
 
     /* Stiffness map */
@@ -37,6 +40,7 @@ public:
 
 public:
     void copy (const Shared_parms *s);
+    void log ();
 };
 
 #endif
diff --git a/src/plastimatch/register/registration_metric_type.cxx b/src/plastimatch/register/similarity_metric_type.cxx
similarity index 59%
rename from src/plastimatch/register/registration_metric_type.cxx
rename to src/plastimatch/register/similarity_metric_type.cxx
index 432da22..a511780 100644
--- a/src/plastimatch/register/registration_metric_type.cxx
+++ b/src/plastimatch/register/similarity_metric_type.cxx
@@ -4,23 +4,25 @@
 #include "plmbase_config.h"
 #include <stdio.h>
 #include <string.h>
-#include "registration_metric_type.h"
+#include "similarity_metric_type.h"
 
 const char* 
-registration_metric_type_string (Registration_metric_type type)
+similarity_metric_type_string (Similarity_metric_type type)
 {
     switch (type) {
-    case REGISTRATION_METRIC_NONE:
+    case SIMILARITY_METRIC_NONE:
         return "none";
-    case REGISTRATION_METRIC_GM:
+    case SIMILARITY_METRIC_DMAP:
+        return "DMAP";
+    case SIMILARITY_METRIC_GM:
         return "GM";
-    case REGISTRATION_METRIC_MI_MATTES:
+    case SIMILARITY_METRIC_MI_MATTES:
         return "MI";
-    case REGISTRATION_METRIC_MI_VW:
+    case SIMILARITY_METRIC_MI_VW:
         return "MIVW";
-    case REGISTRATION_METRIC_MSE:
+    case SIMILARITY_METRIC_MSE:
         return "MSE";
-    case REGISTRATION_METRIC_NMI:
+    case SIMILARITY_METRIC_NMI:
         return "NMI";
     default:
         return "(unkn)";
diff --git a/src/plastimatch/register/similarity_metric_type.h b/src/plastimatch/register/similarity_metric_type.h
new file mode 100644
index 0000000..a54a6fa
--- /dev/null
+++ b/src/plastimatch/register/similarity_metric_type.h
@@ -0,0 +1,19 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _similarity_metric_type_h_
+#define _similarity_metric_type_h_
+
+enum Similarity_metric_type {
+    SIMILARITY_METRIC_NONE,
+    SIMILARITY_METRIC_DMAP,
+    SIMILARITY_METRIC_GM,
+    SIMILARITY_METRIC_MI_MATTES,
+    SIMILARITY_METRIC_MI_VW,
+    SIMILARITY_METRIC_MSE,
+    SIMILARITY_METRIC_NMI
+};
+
+const char* similarity_metric_type_string (Similarity_metric_type);
+
+#endif
diff --git a/src/plastimatch/register/stage_parms.cxx b/src/plastimatch/register/stage_parms.cxx
index 68e5a29..3beec6c 100644
--- a/src/plastimatch/register/stage_parms.cxx
+++ b/src/plastimatch/register/stage_parms.cxx
@@ -50,8 +50,6 @@ Stage_parms::Stage_parms ()
     threading_type = THREADING_CPU_OPENMP;
     gpuid = 0;
     /* Similarity metric */
-    metric_type.push_back (REGISTRATION_METRIC_MSE);
-    metric_lambda.push_back (1.0);
     regularization_type = REGULARIZATION_BSPLINE_ANALYTIC;
     demons_gradient_type = SYMMETRIC;
     regularization_lambda = 0.0f;
@@ -172,8 +170,6 @@ Stage_parms::Stage_parms (const Stage_parms& s)
     threading_type = s.threading_type;
     gpuid = s.gpuid;
     /* Similarity metric */
-    metric_type = s.metric_type;
-    metric_lambda = s.metric_lambda;
     regularization_type = s.regularization_type;
     regularization_lambda = s.regularization_lambda;
     /* Image resample */
diff --git a/src/plastimatch/register/stage_parms.h b/src/plastimatch/register/stage_parms.h
index 80be1ec..3590be2 100644
--- a/src/plastimatch/register/stage_parms.h
+++ b/src/plastimatch/register/stage_parms.h
@@ -10,12 +10,12 @@
 #include <ctype.h>
 #include <stdlib.h>
 
-#include "bspline.h"            /* for enums */
-#include "bspline_mi_hist.h"    /* for enums */
+#include "bspline.h"
+#include "joint_histogram.h"
 #include "plm_image_type.h"
 #include "plm_return_code.h"
 #include "process_parms.h"
-#include "registration_metric_type.h"
+#include "similarity_metric_type.h"
 #include "threading.h"
 
 enum Stage_transform_type {
@@ -127,9 +127,6 @@ public:
     char alg_flavor;
     Threading threading_type;
     int gpuid;               /* Sets GPU to use for multi-gpu machines */
-    /* Similarity metric */
-    std::vector<Registration_metric_type> metric_type;
-    std::vector<float> metric_lambda;
     /* Regularization */
     Regularization_type regularization_type;
     float regularization_lambda;
diff --git a/src/plastimatch/register/translation_grid_search.cxx b/src/plastimatch/register/translation_grid_search.cxx
index 536411c..cc0597b 100644
--- a/src/plastimatch/register/translation_grid_search.cxx
+++ b/src/plastimatch/register/translation_grid_search.cxx
@@ -9,12 +9,14 @@
 #include "interpolate.h"
 #include "interpolate_macros.h"
 #include "logfile.h"
+#include "metric_parms.h"
 #include "mha_io.h"
 #include "plm_image.h"
 #include "plm_image_header.h"
 #include "print_and_exit.h"
 #include "registration_data.h"
 #include "registration_resample.h"
+#include "shared_parms.h"
 #include "stage_parms.h"
 #include "string_util.h"
 #include "translation_grid_search.h"
@@ -26,16 +28,31 @@
 #include "volume_resample.h"
 #include "xform.h"
 
-static void
-translation_grid_search (
-    Xform::Pointer& xf_out, 
-    const Stage_parms* stage,
-    Stage_parms* auto_parms,
+class Translation_grid_search
+{
+public:
+    std::list<Metric_state::Pointer> similarity_data;
+    
     float (*translation_score) (
         const Stage_parms *stage, const Volume::Pointer& fixed,
-        const Volume::Pointer& moving, const float dxyz[3]),
-    const Volume::Pointer& fixed,
-    const Volume::Pointer& moving)
+        const Volume::Pointer& moving, const float dxyz[3]);
+    float best_score;
+    float best_translation[3];
+public:
+    void do_search (
+        Xform::Pointer& xf_out,
+        const Stage_parms* stage,
+        Stage_parms* auto_parms);
+    void do_score (
+        const Stage_parms* stage,
+        const float dxyz[3]);
+};
+
+void
+Translation_grid_search::do_search (
+    Xform::Pointer& xf_out, 
+    const Stage_parms* stage,
+    Stage_parms* auto_parms)
 {
     /* GCS FIX: region of interest is not used */
 
@@ -43,6 +60,9 @@ translation_grid_search (
        For these cases, we need to use bounding box to compute 
        search extent. */
 
+    Volume::Pointer& fixed = this->similarity_data.front()->fixed_ss;
+    Volume::Pointer& moving = this->similarity_data.front()->moving_ss;
+        
     /* Compute maximum search extent */
     lprintf ("Computing grid search extent.\n");
     float search_min[3];
@@ -78,15 +98,11 @@ translation_grid_search (
 
     /* Get default value */
     TranslationTransformType::Pointer old_trn = xf_out->get_trn ();
-    float best_translation[3] = { 0.f, 0.f, 0.f };
-    best_translation[0] = old_trn->GetParameters()[0];
-    best_translation[1] = old_trn->GetParameters()[1];
-    best_translation[2] = old_trn->GetParameters()[2];
-    float best_score = translation_score (
-        stage, fixed, moving, best_translation);
-    lprintf ("[%g %g %g] %g *\n", 
-        best_translation[0], best_translation[1], best_translation[2], 
-        best_score);
+    this->best_translation[0] = old_trn->GetParameters()[0];
+    this->best_translation[1] = old_trn->GetParameters()[1];
+    this->best_translation[2] = old_trn->GetParameters()[2];
+    this->best_score = FLT_MAX;
+    this->do_score (stage, this->best_translation);
 
     /* Compute search range */
     int num_steps[3] = { 0, 0, 0 };
@@ -130,7 +146,7 @@ translation_grid_search (
             } else {
                 search_step[d] = stage->gridsearch_step_size[d];
             }
-            search_min[d] = best_translation[d] - 1.5 * search_step[d];
+            search_min[d] = this->best_translation[d] - 1.5 * search_step[d];
         }
     }
 
@@ -148,27 +164,16 @@ translation_grid_search (
                     search_min[0] + i * search_step[0],
                     search_min[1] + j * search_step[1],
                     search_min[2] + k * search_step[2] };
-                float score = translation_score (stage,
-                    fixed, moving, translation);
-                lprintf ("[%g %g %g] %g", 
-                    translation[0], translation[1], translation[2], score);
-                if (score < best_score) {
-                    best_score = score;
-                    best_translation[0] = translation[0];
-                    best_translation[1] = translation[1];
-                    best_translation[2] = translation[2];
-                    lprintf (" *");
-                }
-                lprintf ("\n");
+                this->do_score (stage, translation);
             }
         }
     }
 
     /* Find the best translation */
     TranslationTransformType::ParametersType xfp(3);
-    xfp[0] = best_translation[0];
-    xfp[1] = best_translation[1];
-    xfp[2] = best_translation[2];
+    xfp[0] = this->best_translation[0];
+    xfp[1] = this->best_translation[1];
+    xfp[2] = this->best_translation[2];
 
     /* Fixate translation into xform */
     TranslationTransformType::Pointer new_trn = TranslationTransformType::New();
@@ -176,6 +181,51 @@ translation_grid_search (
     xf_out->set_trn (new_trn);
 }
 
+void
+Translation_grid_search::do_score (
+    const Stage_parms* stage,
+    const float dxyz[3])
+{
+    lprintf ("[%g %g %g]",
+        dxyz[0], dxyz[1], dxyz[2]);
+
+    std::list<Metric_state::Pointer>::iterator it;
+    float acc_score = 0.f;
+    for (it = this->similarity_data.begin(); 
+         it != this->similarity_data.end(); ++it)
+    {
+        const Metric_state::Pointer& ssi = *it;
+        float score = 0.f;
+        switch (ssi->metric_type) {
+        case SIMILARITY_METRIC_MSE:
+        case SIMILARITY_METRIC_GM:
+            score = translation_mse (stage, ssi, dxyz);
+            break;
+        case SIMILARITY_METRIC_MI_MATTES:
+        case SIMILARITY_METRIC_MI_VW:
+            score = translation_mi (stage, ssi, dxyz);
+            break;
+        default:
+            print_and_exit ("Metric %d not implemented with grid search\n");
+            break;
+        }
+        lprintf (" %g", score);
+        acc_score += score;
+    }
+
+    if (this->similarity_data.size() > 1) {
+        lprintf (" | %g", acc_score);
+    }
+    if (acc_score < this->best_score) {
+        this->best_score = acc_score;
+        this->best_translation[0] = dxyz[0];
+        this->best_translation[1] = dxyz[1];
+        this->best_translation[2] = dxyz[2];
+        lprintf (" *");
+    }
+    lprintf ("\n");
+}
+
 Xform::Pointer
 translation_grid_search_stage (
     Registration_data* regd, 
@@ -185,72 +235,16 @@ translation_grid_search_stage (
     Xform::Pointer xf_out = Xform::New ();
     Plm_image_header pih;
 
-    Volume::Pointer& fixed = regd->fixed_image->get_volume_float ();
-    Volume::Pointer& moving = regd->moving_image->get_volume_float ();
-    Volume::Pointer moving_ss;
-    Volume::Pointer fixed_ss;
+    Translation_grid_search tgsd;
 
-    fixed->convert (PT_FLOAT);              /* Maybe not necessary? */
-    moving->convert (PT_FLOAT);             /* Maybe not necessary? */
+    /* Copy similarity images and parms */
+    populate_similarity_list (tgsd.similarity_data, regd, stage);
 
-#if defined (commentout)
-    lprintf ("SUBSAMPLE: (%g %g %g), (%g %g %g)\n", 
-	stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], 
-	stage->resample_rate_fixed[2], stage->resample_rate_moving[0], 
-	stage->resample_rate_moving[1], stage->resample_rate_moving[2]
-    );
-    moving_ss = volume_subsample_vox_legacy (
-        moving, stage->resample_rate_moving);
-    fixed_ss = volume_subsample_vox_legacy (
-        fixed, stage->resample_rate_fixed);
-#endif
-    moving_ss = registration_resample_volume (
-        moving, stage, stage->resample_rate_moving);
-    fixed_ss = registration_resample_volume (
-        fixed, stage, stage->resample_rate_fixed);
-
-    if (stage->metric_type[0] == REGISTRATION_METRIC_GM) {
-        fixed_ss = volume_gradient_magnitude (fixed_ss);
-        moving_ss = volume_gradient_magnitude (moving_ss);
-    }
-    
-    if (stage->debug_dir != "") {
-        std::string fn;
-        fn = string_format ("%s/%02d_fixed_ss.mha",
-            stage->debug_dir.c_str(), stage->stage_no);
-        write_mha (fn.c_str(), fixed_ss.get());
-        fn = string_format ("%s/%02d_moving_ss.mha",
-            stage->debug_dir.c_str(), stage->stage_no);
-        write_mha (fn.c_str(), moving_ss.get());
-    }
-        
     /* Transform input xform to itk translation */
     xform_to_trn (xf_out.get(), xf_in.get(), &pih);
 
-    /* Choose the correct score function */
-    float (*translation_score) (
-        const Stage_parms *stage, const Volume::Pointer& fixed,
-        const Volume::Pointer& moving, const float dxyz[3]) 
-        = &translation_mse;
-    switch (stage->metric_type[0]) {
-    case REGISTRATION_METRIC_MSE:
-    case REGISTRATION_METRIC_GM:
-        translation_score = &translation_mse;
-        break;
-    case REGISTRATION_METRIC_MI_MATTES:
-    case REGISTRATION_METRIC_MI_VW:
-        translation_score = &translation_mi;
-        break;
-    default:
-        print_and_exit ("Metric %d not implemented with grid search\n");
-        break;
-    }
-
     /* Run the translation optimizer */
-    translation_grid_search (xf_out, stage, 
-        regd->get_auto_parms (), 
-        translation_score, 
-        fixed_ss, moving_ss);
+    tgsd.do_search (xf_out, stage, regd->get_auto_parms ());
 
     return xf_out;
 }
diff --git a/src/plastimatch/register/translation_mi.cxx b/src/plastimatch/register/translation_mi.cxx
index 9c6ee26..9061466 100644
--- a/src/plastimatch/register/translation_mi.cxx
+++ b/src/plastimatch/register/translation_mi.cxx
@@ -22,24 +22,18 @@
 float
 translation_mi (
     const Stage_parms *stage,
-    const Volume::Pointer& fixed,
-    const Volume::Pointer& moving,
+    const Metric_state::Pointer& ssi,
     const float dxyz[3])
 {
-    Bspline_mi_hist_set *mi_hist = new Bspline_mi_hist_set (
+    Volume *fixed = ssi->fixed_ss.get();
+    Volume *moving = ssi->moving_ss.get();
+    Joint_histogram *mi_hist = new Joint_histogram (
         stage->mi_hist_type,
         stage->mi_hist_fixed_bins,
         stage->mi_hist_moving_bins);
-    mi_hist->initialize (fixed.get(), moving.get());
+    mi_hist->initialize (fixed, moving);
     mi_hist->reset_histograms ();
         
-    float mse_score = 0.0f;
-    double* f_hist = mi_hist->f_hist;
-    double* m_hist = mi_hist->m_hist;
-    double* j_hist = mi_hist->j_hist;
-    double mhis = 0.0f;      /* Moving histogram incomplete sum */
-    double jhis = 0.0f;      /* Joint  histogram incomplete sum */
-
     plm_long fijk[3], fidx;       /* Indices within fixed image (vox) */
     float fxyz[3];                /* Position within fixed image (mm) */
     float mijk[3];                /* Indices within moving image (vox) */
@@ -67,7 +61,7 @@ translation_mi (
                 if (!moving->is_inside (mijk)) continue;
 
                 /* Get tri-linear interpolation fractions */
-                li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving.get());
+                li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving);
                     
                 /* Find the fixed image linear index */
                 fidx = volume_index (fixed->dim, fijk);
@@ -78,8 +72,7 @@ translation_mi (
                 midx_f = volume_index (moving->dim, mijk_f);
 
                 /* Add to histogram */
-                mi_hist->add_pvi_8 (
-                    fixed.get(), moving.get(), fidx, midx_f, li_1, li_2);
+                mi_hist->add_pvi_8 (fixed, moving, fidx, midx_f, li_1, li_2);
 
                 num_vox++;
             }
diff --git a/src/plastimatch/register/translation_mi.h b/src/plastimatch/register/translation_mi.h
index 53c29f8..0d9bad8 100644
--- a/src/plastimatch/register/translation_mi.h
+++ b/src/plastimatch/register/translation_mi.h
@@ -12,8 +12,7 @@ class Stage_parms;
 float
 translation_mi (
     const Stage_parms *stage,
-    const Volume::Pointer& fixed,
-    const Volume::Pointer& moving,
+    const Metric_state::Pointer& ssi,
     const float dxyz[3]);
 
 #endif
diff --git a/src/plastimatch/register/translation_mse.cxx b/src/plastimatch/register/translation_mse.cxx
index 8cce5cb..dfcd4ad 100644
--- a/src/plastimatch/register/translation_mse.cxx
+++ b/src/plastimatch/register/translation_mse.cxx
@@ -22,8 +22,7 @@
 float
 translation_mse (
     const Stage_parms *stage,
-    const Volume::Pointer& fixed,
-    const Volume::Pointer& moving,
+    const Metric_state::Pointer& ssi,
     const float dxyz[3])
 {
     plm_long fijk[3], fv;         /* Indices within fixed image (vox) */
@@ -37,7 +36,8 @@ translation_mse (
     plm_long mijk_r[3];           /* Round */
     float m_val;
 
-    Volume *mvol = moving.get();
+    Volume *fixed = ssi->fixed_ss.get();
+    Volume *moving = ssi->moving_ss.get();
     float* f_img = (float*) fixed->img;
     float* m_img = (float*) moving->img;
 
@@ -59,7 +59,7 @@ translation_mse (
                 if (!moving->is_inside (mijk)) continue;
 
                 /* Compute interpolation fractions */
-                li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, mvol);
+                li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving);
 
                 /* Find linear index of "corner voxel" in moving image */
                 mvf = volume_index (moving->dim, mijk_f);
diff --git a/src/plastimatch/register/translation_mse.h b/src/plastimatch/register/translation_mse.h
index 82a3173..6ac8025 100644
--- a/src/plastimatch/register/translation_mse.h
+++ b/src/plastimatch/register/translation_mse.h
@@ -10,8 +10,7 @@
 float
 translation_mse (
     const Stage_parms *stage,
-    const Volume::Pointer& fixed,
-    const Volume::Pointer& moving,
+    const Metric_state::Pointer& ssi,
     const float dxyz[3]);
 
 #endif
diff --git a/src/plastimatch/segment/autolabel_parms.cxx b/src/plastimatch/segment/autolabel_parms.cxx
index a6c7779..0c76907 100644
--- a/src/plastimatch/segment/autolabel_parms.cxx
+++ b/src/plastimatch/segment/autolabel_parms.cxx
@@ -71,9 +71,10 @@ public:
     virtual Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key, 
+        const std::string& index, 
         const std::string& val)
     {
-        return this->mp->set_key_value (section, key, val);
+        return this->mp->set_key_value (section, key, index, val);
     }
 };
 
@@ -110,6 +111,7 @@ Plm_return_code
 Autolabel_parms::set_key_value (
     const std::string& section, 
     const std::string& key, 
+    const std::string& index, 
     const std::string& val
 )
 {
diff --git a/src/plastimatch/segment/autolabel_parms.h b/src/plastimatch/segment/autolabel_parms.h
index 7629f93..aca33cf 100644
--- a/src/plastimatch/segment/autolabel_parms.h
+++ b/src/plastimatch/segment/autolabel_parms.h
@@ -27,6 +27,7 @@ public:
     Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key, 
+        const std::string& index, 
         const std::string& val);
 
 public:
diff --git a/src/plastimatch/segment/mabs.cxx b/src/plastimatch/segment/mabs.cxx
old mode 100755
new mode 100644
index 96e1d45..8624979
--- a/src/plastimatch/segment/mabs.cxx
+++ b/src/plastimatch/segment/mabs.cxx
@@ -576,7 +576,7 @@ Mabs::run_registration_loop ()
                 std::string command_string_plus_cog = "[STAGE]\nxform=align_center_of_gravity\n";
                 command_string_plus_cog.append(command_string);
                 int rc_cog = reg.set_command_string (command_string_plus_cog);
-                if (rc != PLM_SUCCESS) {
+                if (rc_cog != PLM_SUCCESS) {
                     lprintf ("Skipping centers of gravity prealignment addition to command file \"%s\" \n", command_file.c_str());
                     continue;
                 }
@@ -621,11 +621,11 @@ Mabs::run_registration_loop ()
 
             /* Warp the output image */
             lprintf ("Warp output image...\n");
-            Plm_image_header fixed_pih (regd->fixed_image);
+            Plm_image_header fixed_pih (fixed_image);
             Plm_image::Pointer warped_image = Plm_image::New();
             timer.start();
             plm_warp (warped_image, 0, xf_out, &fixed_pih, 
-                regd->moving_image, 
+                moving_image, 
                 regp->default_value, 0, 1);
             d_ptr->time_warp_img += timer.report();
             
@@ -933,7 +933,7 @@ Mabs::atlas_selection ()
                 std::string command_string_plus_cog = "[STAGE]\nxform=align_center_of_gravity\n";
                 command_string_plus_cog.append(command_string);
                 int rc_cog = reg.set_command_string (command_string_plus_cog);
-                if (rc != PLM_SUCCESS) {
+                if (rc_cog != PLM_SUCCESS) {
                     lprintf ("Skipping centers of gravity prealignment addition to command file \"%s\" \n", d_ptr->parms->prealign_registration_config.c_str());
                 }
             
@@ -961,11 +961,11 @@ Mabs::atlas_selection ()
         
             /* Warp the image */
             lprintf ("Prealign input image...\n");
-            Plm_image_header fixed_pih (regd->fixed_image);
+            Plm_image_header fixed_pih (fixed_image);
             Plm_image::Pointer warped_image = Plm_image::New();
             timer.start();
             plm_warp (warped_image, 0, xf_out, &fixed_pih,
-                regd->moving_image,
+                moving_image,
                 regp->default_value, 0, 1);
             d_ptr->time_warp_img += timer.report();
 
diff --git a/src/plastimatch/segment/mabs.h b/src/plastimatch/segment/mabs.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/segment/mabs_atlas_selection.cxx b/src/plastimatch/segment/mabs_atlas_selection.cxx
index a35765c..35d2f9a 100644
--- a/src/plastimatch/segment/mabs_atlas_selection.cxx
+++ b/src/plastimatch/segment/mabs_atlas_selection.cxx
@@ -248,7 +248,7 @@ Mabs_atlas_selection::compute_similarity_value_post()
     Xform::Pointer xf = reg.do_registration_pure ();
 
     Plm_image::Pointer deformed_atlas = Plm_image::New ();
-    Plm_image_header fixed_pih (regd->fixed_image);
+    Plm_image_header fixed_pih (this->subject);
     plm_warp (deformed_atlas, 0, xf, &fixed_pih, 
         this->atlas, regp->default_value, 0, 1);
    
@@ -289,7 +289,7 @@ Mabs_atlas_selection::compute_similarity_value_ratio()
     Xform::Pointer xf = reg.do_registration_pure ();
 
     Plm_image::Pointer deformed_atlas = Plm_image::New ();
-    Plm_image_header fixed_pih (regd->fixed_image);
+    Plm_image_header fixed_pih (this->subject);
     plm_warp (deformed_atlas, 0, xf, &fixed_pih, 
         this->atlas, regp->default_value, 0, 1);
 
diff --git a/src/plastimatch/segment/mabs_parms.cxx b/src/plastimatch/segment/mabs_parms.cxx
index dead18e..4482fa1 100644
--- a/src/plastimatch/segment/mabs_parms.cxx
+++ b/src/plastimatch/segment/mabs_parms.cxx
@@ -83,6 +83,7 @@ public:
     virtual Plm_return_code set_key_value (
         const std::string& section,
         const std::string& key, 
+        const std::string& index, 
         const std::string& val);
 };
 
@@ -90,6 +91,7 @@ Plm_return_code
 Mabs_parms_parser::set_key_value (
     const std::string& section,
     const std::string& key, 
+    const std::string& index, 
     const std::string& val)
 {
     /* [CONVERT] */
diff --git a/src/plastimatch/segment/mabs_stats.cxx b/src/plastimatch/segment/mabs_stats.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/segment/mabs_stats.h b/src/plastimatch/segment/mabs_stats.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/CMakeLists.txt b/src/plastimatch/standalone/CMakeLists.txt
index d7cfd94..901388b 100644
--- a/src/plastimatch/standalone/CMakeLists.txt
+++ b/src/plastimatch/standalone/CMakeLists.txt
@@ -83,9 +83,6 @@ set (OPENCL_PROBE_SRC
 if (OPENCL_FOUND)
   plm_add_opencl_file (OPENCL_PROBE_SRC opencl_probe.cl)
 endif ()
-set (PROTON_DOSE_SRC
-  proton_dose_main.cxx 
-  )
 set (RAW_TO_MHA_SRC
   raw_to_mha.c
   )
@@ -351,9 +348,6 @@ plm_add_executable (hnd_to_pfm "${HND_TO_PFM_SRC}"
 plm_add_executable (mha_to_raw "${MHA_TO_RAW_SRC}"
   "" ""
   ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER})
-plm_add_executable (proton_dose "${PROTON_DOSE_SRC}" 
-  "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" 
-  ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER})
 plm_add_executable (raw_to_mha "${RAW_TO_MHA_SRC}"
   "" "" 
   ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER})
diff --git a/src/plastimatch/standalone/YKThreadRegi.cpp b/src/plastimatch/standalone/YKThreadRegi.cpp
index 70001b3..cfe8123 100644
--- a/src/plastimatch/standalone/YKThreadRegi.cpp
+++ b/src/plastimatch/standalone/YKThreadRegi.cpp
@@ -53,10 +53,6 @@ void YKThreadRegi::run()//called by thread.start()
             strPath.c_str());
     }
 
-    std::string strFixed = reg.get_registration_parms()->get_fixed_fn(); //  return d_ptr->rparms;
-    std::string strMoving = reg.get_registration_parms()->get_moving_fn();   
-
-
     QTime time;
     time.start();
     try {
diff --git a/src/plastimatch/standalone/bspline_main.cxx b/src/plastimatch/standalone/bspline_main.cxx
index d1c9a77..f2a3962 100644
--- a/src/plastimatch/standalone/bspline_main.cxx
+++ b/src/plastimatch/standalone/bspline_main.cxx
@@ -49,22 +49,6 @@ main (int argc, char* argv[])
     }
 #endif
 
-    fixed = read_mha (options.fixed_fn);
-    if (!fixed) exit (-1);
-    moving = read_mha (options.moving_fn);
-    if (!moving) exit (-1);
-
-    parms->fixed = fixed;
-    parms->moving = moving;
-
-    volume_convert_to_float (moving);
-    volume_convert_to_float (fixed);
-
-    printf ("Making gradient\n");
-    moving_grad = volume_make_gradient (moving);
-
-    parms->moving_grad = moving_grad;
-
 #if defined (commentout)
     /* Load and adjust landmarks */
     if (options.fixed_landmarks && options.moving_landmarks) {
@@ -77,6 +61,12 @@ main (int argc, char* argv[])
     /* Debug */
     //write_mha ("moving_grad.mha", moving_grad);
 
+    /* Load images */
+    fixed = read_mha (options.fixed_fn);
+    if (!fixed) exit (-1);
+    moving = read_mha (options.moving_fn);
+    if (!moving) exit (-1);
+
     /* Allocate memory and build lookup tables */
     printf ("Allocating lookup tables\n");
     memset (roi_offset, 0, 3*sizeof(plm_long));
@@ -99,9 +89,31 @@ main (int argc, char* argv[])
         );
     }
 
+    /* Initialize Bspline_optimize data structure */
+    Bspline_optimize bod;
+    Bspline_state *bst = bod.get_bspline_state();
+
+    /* Set up Metric_state */
+    Metric_state::Pointer ms = Metric_state::New ();
+    ms->metric_type = options.metric_type;
+    printf ("Metric type %d\n", ms->metric_type);
+    ms->metric_lambda = 1.f;
+    ms->fixed_ss.reset (fixed);
+    ms->moving_ss.reset (moving);
+    bst->similarity_data.push_back (ms);
+
+    volume_convert_to_float (moving);
+    volume_convert_to_float (fixed);
+
+    printf ("Making gradient\n");
+    moving_grad = volume_make_gradient (ms->moving_ss.get());
+    ms->moving_grad.reset (moving_grad);
+
     /* Run the optimization */
     printf ("Running optimization.\n");
-    bspline_optimize (bxf, parms);
+    bod.set_bspline_parms (parms);
+    bod.set_bspline_xform (bxf);
+    bod.optimize ();
     printf ("Done running optimization.\n");
 
     /* Save output transform */
@@ -157,9 +169,6 @@ main (int argc, char* argv[])
     /* Free memory */
     printf ("Done warping images.\n");
     delete bxf;
-    delete fixed;
-    delete moving;
-    delete moving_grad;
     delete moving_warped;
     delete vector_field;
 
diff --git a/src/plastimatch/standalone/bspline_opts.cxx b/src/plastimatch/standalone/bspline_opts.cxx
index c5e3d7b..e7b5711 100644
--- a/src/plastimatch/standalone/bspline_opts.cxx
+++ b/src/plastimatch/standalone/bspline_opts.cxx
@@ -175,13 +175,12 @@ bspline_opts_parse_args (Bspline_options* options, int argc, char* argv[])
 	    }
 	    i++;
 	    if (!strcmp(argv[i], "mse")) {
-		parms->metric_type[0] = REGISTRATION_METRIC_MSE;
+		options->metric_type = SIMILARITY_METRIC_MSE;
 	    } else if (!strcmp(argv[i], "mi")) {
-		parms->metric_type[0] = REGISTRATION_METRIC_MI_MATTES;
+		options->metric_type = SIMILARITY_METRIC_MI_MATTES;
 	    } else {
 		print_usage ();
 	    }
-            parms->metric_lambda[0] = 1.;
 	}
 	else if (!strcmp (argv[i], "-s")) {
 	    if (i == (argc-1) || argv[i+1][0] == '-') {
diff --git a/src/plastimatch/standalone/bspline_opts.h b/src/plastimatch/standalone/bspline_opts.h
index d99725c..1a70981 100644
--- a/src/plastimatch/standalone/bspline_opts.h
+++ b/src/plastimatch/standalone/bspline_opts.h
@@ -6,6 +6,7 @@
 
 #include "bspline.h"
 #include "bspline_parms.h"
+#include "similarity_metric_type.h"
 
 class Bspline_options
 {
@@ -20,6 +21,7 @@ public:
     char* moving_landmarks;
     char* warped_landmarks;
     char* method;
+    Similarity_metric_type metric_type;
     float landmark_stiffness;
     float young_modulus;
     plm_long vox_per_rgn[3];
@@ -36,6 +38,7 @@ public:
 	moving_landmarks = 0;
 	warped_landmarks = 0;
 	method = 0;
+        metric_type = SIMILARITY_METRIC_MSE;
 	landmark_stiffness = 0;
 	young_modulus = 0;
 	for (int d = 0; d < 3; d++) {
diff --git a/src/plastimatch/standalone/check_grad.cxx b/src/plastimatch/standalone/check_grad.cxx
index e7580d2..faa6943 100644
--- a/src/plastimatch/standalone/check_grad.cxx
+++ b/src/plastimatch/standalone/check_grad.cxx
@@ -19,7 +19,7 @@
 #include "plm_clp.h"
 #include "plm_image.h"
 #include "print_and_exit.h"
-#include "registration_metric_type.h"
+#include "similarity_metric_type.h"
 #include "volume.h"
 #include "volume_grad.h"
 
@@ -53,7 +53,7 @@ public:
 
     char bsp_implementation;
     BsplineThreading bsp_threading;
-    Registration_metric_type bsp_metric;
+    Similarity_metric_type bsp_metric;
 
 public:
     Check_grad_opts () {
@@ -74,7 +74,7 @@ public:
         debug_dir = "";
         bsp_implementation = '\0';
         bsp_threading = BTHR_CPU;
-        bsp_metric = REGISTRATION_METRIC_MSE;
+        bsp_metric = SIMILARITY_METRIC_MSE;
     }
 };
 
@@ -93,19 +93,22 @@ check_gradient (
     Bspline_optimize bod;
     Bspline_xform *bxf;
     Bspline_parms *parms = new Bspline_parms;
+    Bspline_state *bst = bod.get_bspline_state ();
 
     /* Fixate images into bspline parms */
-    parms->fixed = fixed;
-    parms->moving = moving;
-    parms->moving_grad = moving_grad;
+    Metric_state::Pointer sim = Metric_state::New();
+    bst->similarity_data.push_back (sim);
     parms->implementation = options->bsp_implementation;
-    parms->metric_type[0] = options->bsp_metric;
+    sim->fixed_ss.reset (fixed);
+    sim->moving_ss.reset (moving);
+    sim->moving_grad.reset (moving_grad);
+    sim->metric_type = options->bsp_metric;
 
     /* Maybe we got a roi too */
     Plm_image::Pointer pli_fixed_roi;
     if (options->fixed_roi_fn != "") {
         pli_fixed_roi = Plm_image::New (options->fixed_roi_fn);
-        parms->fixed_roi = pli_fixed_roi->get_volume_uchar().get();
+        sim->fixed_roi = pli_fixed_roi->get_volume_uchar();
     }
 
     /* Set extra debug stuff, if desired */
@@ -140,8 +143,8 @@ check_gradient (
             }
         }
     }
-    bod.initialize (bxf, parms);
-    Bspline_state *bst = bod.get_bspline_state ();
+    bod.set_bspline_xform (bxf);
+    bod.set_bspline_parms (parms);
 
     /* Create scratch variables */
     x = (float*) malloc (sizeof(float) * bxf->num_coeff);
@@ -153,9 +156,7 @@ check_gradient (
         x[i] = bxf->coeff[i];
     }
 
-    if (parms->metric_type[0] == REGISTRATION_METRIC_MI_MATTES) {
-        bst->mi_hist->initialize (parms->fixed, parms->moving);
-    }
+    bst->initialize_mi_histograms ();
 
     /* Get score and gradient */
     bspline_score (&bod);
@@ -167,7 +168,7 @@ check_gradient (
     for (i = 0; i < bxf->num_coeff; i++) {
         grad[i] = bst->ssd.total_grad[i];
     }
-    score = bst->ssd.score;
+    score = bst->ssd.total_score;
 
     /* If a search dir was specified, use that instead of the gradient */
     if (options->input_search_dir_fn != "") {
@@ -213,7 +214,7 @@ check_gradient (
             }
         
             /* Compute difference between grad and grad_fd */
-            fprintf (fp, "%4d,%12.12f\n", i, bst->ssd.score);
+            fprintf (fp, "%4d,%12.12f\n", i, bst->ssd.total_score);
 
             // JAS 04.19.2010
             // This loop could take a while to exit.  This will
@@ -246,7 +247,7 @@ check_gradient (
             }
         
             /* Stash score difference in grad_fd */
-            grad_fd[i] = (bst->ssd.score - score) / options->step_size;
+            grad_fd[i] = (bst->ssd.total_score - score) / options->step_size;
 
             /* Compute difference between grad and grad_fd */
             fprintf (fp, "%12.12f,%12.12f\n", grad[i], grad_fd[i]);
@@ -360,9 +361,9 @@ parse_fn (
     }
     val = parser->get_string("metric").c_str();
     if (val == "mse") {
-        parms->bsp_metric = REGISTRATION_METRIC_MSE;
+        parms->bsp_metric = SIMILARITY_METRIC_MSE;
     } else if (val == "mi") {
-        parms->bsp_metric = REGISTRATION_METRIC_MI_MATTES;
+        parms->bsp_metric = SIMILARITY_METRIC_MI_MATTES;
     } else {
         throw (dlib::error ("Error parsing --metric, unknown option."));
     }
diff --git a/src/plastimatch/standalone/dlib_train.cxx b/src/plastimatch/standalone/dlib_train.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/drr_main.cxx b/src/plastimatch/standalone/drr_main.cxx
old mode 100644
new mode 100755
index 35d44e5..699ee78
--- a/src/plastimatch/standalone/drr_main.cxx
+++ b/src/plastimatch/standalone/drr_main.cxx
@@ -119,8 +119,8 @@ create_matrix_and_drr (
 		     options->image_center[1] };
 
     /* Set image resolution */
-    int ires[2] = { options->image_resolution[0],
-		    options->image_resolution[1] };
+    plm_long ires[2] = { options->image_resolution[0],
+                         options->image_resolution[1] };
 
     /* Set physical size of imager in mm */
     float isize[2];
@@ -133,7 +133,7 @@ create_matrix_and_drr (
 
     /* Create projection matrix */
     sprintf (mat_fn, "%s%04d.txt", options->output_prefix, a);
-    pmat->set (cam, tgt, vup, sid, ic, ps, ires);
+    pmat->set (cam, tgt, vup, sid, ic, ps);
 
     if (options->output_format == OUTPUT_FORMAT_PFM) {
 	sprintf (img_fn, "%s%04d.pfm", options->output_prefix, a);
diff --git a/src/plastimatch/standalone/gamma_gui.cpp b/src/plastimatch/standalone/gamma_gui.cpp
index ee54236..6533d5b 100644
--- a/src/plastimatch/standalone/gamma_gui.cpp
+++ b/src/plastimatch/standalone/gamma_gui.cpp
@@ -3354,3 +3354,320 @@ QString gamma_gui::ConvertMGHProtonDoseToMha(QString& strPathBinary, VEC3D& fDim
     
     return strResult;
 }
+
+void gamma_gui::SLTM_ConvertIBAOPG_Files()
+{
+	QStringList files = QFileDialog::getOpenFileNames(this, "Select one or more files to open",
+		m_strPathInputDir, "IBA OPG files (*.opg)");
+
+	int cnt = files.size();
+	if (cnt <= 0)
+		return;
+
+	QString strPathOPG;
+	QString strPathMHA;
+	int filePathLen;
+	for (int i = 0; i < cnt; i++)
+	{
+		strPathOPG = files.at(i);
+		filePathLen = strPathOPG.length();
+		//replace extention
+		strPathMHA = strPathOPG.left(filePathLen - 4);
+		strPathMHA = strPathMHA + ".mha";
+		ConvertOPG2FloatMHA(strPathOPG, strPathMHA);
+	}
+}
+
+
+//From IBA generic Txt (OPG) to float mha
+bool gamma_gui::ConvertOPG2FloatMHA(QString& strFilePathOPG, QString& strFilePathMHA)
+{
+	//FloatImage2DType::Pointer spFloatDose;       
+
+
+	//Data Type:          Abs. Dose
+	//Data Factor : 1.814
+	//Data Unit : Should be mGy
+	// Length unit: should be cm
+	//No.of Columns : 32
+	//  No.of Rows : 32
+	//Number of Bodies:   1
+	//Operators Note : Corr. : Unif.Calib., Bkgnd, Calib Output, Temp., Press.,
+
+	bool bAbsDose = false;
+	double fDataFactor = 0.0;
+	QString strDataUnit;
+	QString strLengthUnit;
+	int iColumns = 0;
+	int iRows = 0;
+	int iBody = 0;
+	QString strNote;
+
+	double fPlanePos = 0.0;
+
+	ifstream fin;
+	fin.open(strFilePathOPG.toLocal8Bit().constData());
+
+	if (fin.fail())
+	{
+		cout << "Error occurred in file reading!" << endl;
+		return false;
+	}
+	char str[MAX_LINE_LENGTH];
+
+	vector<double> vXVal;
+	vector<double> vYVal;
+	float* pFloatImg = NULL;
+	int imgSize = 0;
+
+	while (!fin.eof())
+	{
+		memset(str, 0, MAX_LINE_LENGTH);
+		fin.getline(str, MAX_LINE_LENGTH);
+		QString tmpStr = QString(str);
+		QString trimmed;
+		QStringList strListLine;
+		QString strHeader;
+		QString strData;
+
+		if (tmpStr.contains("<asciiheader>")) //go into subloop
+		{
+			while (!fin.eof())
+			{
+				strHeader = "";
+				strData = "";
+
+				memset(str, 0, MAX_LINE_LENGTH);
+				fin.getline(str, MAX_LINE_LENGTH);
+				tmpStr = QString(str);
+
+				strListLine = tmpStr.split("  ");// at least two consec. spaces
+
+				if (strListLine.count() >= 2)
+				{
+					strHeader = strListLine.at(0);
+					strData = tmpStr.right(tmpStr.length() - strHeader.length());
+					strData = strData.trimmed();
+				}
+
+				//trimmed = tmpStr.trimmed(); //if any blank line found
+				//if (trimmed.length() < 1)
+				//    break;
+
+				if (strHeader.contains("Data Type:") && strData.length() > 0) //go into subloop                
+				{
+					if (strData.contains("Abs. Dose"))
+						bAbsDose = true;
+					else
+						bAbsDose = false;
+				}
+				else if (strHeader.contains("Data Factor:") && strData.length() > 0) //go into subloop                
+				{
+					fDataFactor = strData.toDouble();
+				}
+				else if (strHeader.contains("Data Unit:") && strData.length() > 0) //go into subloop                
+				{
+					strDataUnit = strData;
+					if (!strDataUnit.contains("mGy"))
+					{
+						cout << "Error! unit should be mGy. Current = " << strDataUnit.toLocal8Bit().constData() << endl;
+					}
+				}
+				else if (strHeader.contains("Length Unit:") && strData.length() > 0) //go into subloop                
+				{
+					strLengthUnit = strData;
+
+					if (!strLengthUnit.contains("cm"))
+					{
+						cout << "Error! unit should be cm. Current = " << strLengthUnit.toLocal8Bit().constData() << endl;
+					}
+				}
+				else if (strHeader.contains("No. of Columns:") && strData.length() > 0) //go into subloop                
+				{
+					iColumns = strData.toInt();
+				}
+				else if (strHeader.contains("No. of Rows:") && strData.length() > 0) //go into subloop                
+				{
+					iRows = strData.toInt();
+				}
+				else if (strHeader.contains("Number of Bodies:") && strData.length() > 0) //go into subloop                
+				{
+					iBody = strData.toInt();
+				}
+				else if (strHeader.contains("Operators Note:") && strData.length() > 0) //go into subloop                
+				{
+					strNote = strData;
+				}
+				//else if (strHeader.contains("</asciiheader>")) //go into subloop                          
+				else if (tmpStr.contains("</asciiheader>")) //go into subloop                                            
+				{
+					break;
+				}
+			}// end of while
+		}//end of if tmpStr.contains("<asciiheader>"     
+
+		if (tmpStr.contains("<asciibody>")) //go into subloop
+		{
+			imgSize = iColumns*iRows;
+
+			if (imgSize > 1)
+				pFloatImg = new float[imgSize];
+
+			while (!fin.eof())
+			{
+				memset(str, 0, MAX_LINE_LENGTH);
+				fin.getline(str, MAX_LINE_LENGTH);
+				tmpStr = QString(str);
+
+				if (tmpStr.contains("X[cm]"))
+				{
+					strListLine = tmpStr.split(" ");
+					int iCntItem = strListLine.count();
+					vXVal.clear();
+
+					QStringList strListValidX;
+					QString strTestX;
+
+					for (int i = 1; i<iCntItem; i++)
+					{
+						strTestX = strListLine.at(i);
+						cout << strTestX.toLocal8Bit().constData() << endl;
+
+						strTestX = strTestX.trimmed();
+						if (strTestX.length() > 0)
+						{
+							strListValidX.push_back(strTestX);
+						}
+					}
+
+					int iValidXCnt = strListValidX.count();
+
+					cout << "Valid only" << endl;
+					for (int i = 0; i < iValidXCnt; i++)
+					{
+						vXVal.push_back(strListValidX.at(i).toDouble());
+						cout << strListValidX.at(i).toDouble() << endl;
+					}
+
+					/*if ((int)(vXVal.size()) != iColumns)
+					{
+					cout << "Error! X[cm] data count = " << vXVal.size() << ", X header info = " << iColumns << endl;
+					return false;
+					}    */
+				}
+				else if (tmpStr.contains("Y[cm]"))
+				{
+					vYVal.clear();
+					int iYLineCnt = 0;
+
+					while (!fin.eof())
+					{
+						memset(str, 0, MAX_LINE_LENGTH);
+						fin.getline(str, MAX_LINE_LENGTH);
+						tmpStr = QString(str);
+
+						if (tmpStr.contains("</asciibody>"))
+							break;
+
+						strListLine = tmpStr.split("\t");// at least two consec. spaces
+
+						int iDataCnt = strListLine.count();
+
+						if (iDataCnt > 1)
+						{
+							vYVal.push_back(strListLine.at(0).toDouble());
+						}
+
+						QStringList strListValid;
+						QString strTest;
+						for (int i = 1; i<iDataCnt; i++)
+						{
+							strTest = strListLine.at(i);
+							strTest = strTest.trimmed();
+							if (strTest.length() > 0)
+							{
+								strListValid.push_back(strTest);
+							}
+						}
+
+						if (strListValid.count() != iColumns)
+						{
+							cout << "Error! X data count = " << strListValid.count() << " vs " << iColumns << endl;
+							return false;
+						}
+
+						int curIdx = 0;
+						for (int i = 0; i < iColumns; i++)
+						{
+							curIdx = iColumns*iYLineCnt + i;
+							if (curIdx < imgSize)
+								pFloatImg[curIdx] = (strListValid.at(i).toDouble())*fDataFactor / 1000.0; //Unit: Gy
+						}
+						iYLineCnt++;
+					}//end of sub while
+
+					if (iYLineCnt != iRows)
+					{
+						cout << "Error! Y data count = " << iYLineCnt << " vs " << iRows << endl;
+						return false;
+					}
+				}// end of Y cm
+			}//end of asciibody while
+		}//if asciibody       
+	} // main while
+	fin.close();
+
+	//img array to itk image
+
+	if (vXVal.size() < 2 || vYVal.size() < 2)
+		return false;
+
+	FloatImage2DType::PointType ptOriginItk;
+	FloatImage2DType::SizeType imgSizeItk;
+	FloatImage2DType::SpacingType imgSpacingItk;
+
+	ptOriginItk[0] = vXVal.at(0)*10.0;
+	ptOriginItk[1] = vYVal.at(0)*10.0;
+
+	imgSizeItk[0] = iColumns;
+	imgSizeItk[1] = iRows;
+
+	imgSpacingItk[0] = fabs(vXVal.at(1) - vXVal.at(0))*10.0; // cm to mm
+	imgSpacingItk[1] = fabs(vYVal.at(1) - vYVal.at(0))*10.0;
+
+	FloatImage2DType::IndexType idxStart;
+	idxStart[0] = 0;
+	idxStart[1] = 0;
+
+	FloatImage2DType::RegionType region;
+	region.SetSize(imgSizeItk);
+	region.SetIndex(idxStart);
+
+	FloatImage2DType::Pointer spFloatDoseImg = FloatImage2DType::New();
+	spFloatDoseImg->SetRegions(region);
+	spFloatDoseImg->SetSpacing(imgSpacingItk);
+	spFloatDoseImg->SetOrigin(ptOriginItk);
+
+	spFloatDoseImg->Allocate();
+	spFloatDoseImg->FillBuffer(0.0);
+
+	itk::ImageRegionIterator<FloatImage2DType> it(spFloatDoseImg, spFloatDoseImg->GetLargestPossibleRegion());
+
+	int idx = 0;
+	for (it.GoToBegin(); !it.IsAtEnd(); ++it)
+	{
+		if (idx < imgSize)
+		{
+			float curVal = pFloatImg[idx];
+			it.Set(curVal);
+		}
+		idx++;
+	}
+
+	if (pFloatImg != NULL)
+		delete[] pFloatImg;
+
+	QUTIL::SaveFloatImage2D(strFilePathMHA.toLocal8Bit().constData(), spFloatDoseImg);
+
+	return true;
+}
diff --git a/src/plastimatch/standalone/gamma_gui.h b/src/plastimatch/standalone/gamma_gui.h
index af1753a..19ebf76 100644
--- a/src/plastimatch/standalone/gamma_gui.h
+++ b/src/plastimatch/standalone/gamma_gui.h
@@ -58,6 +58,8 @@ public:
 
     QString ConvertMGHProtonDoseToMha(QString& strPathBinnary, VEC3D& fDim, VEC3D& fOrigin, VEC3D& fSpacing);
 
+	bool ConvertOPG2FloatMHA(QString& strFilePathOPG, QString& strFilePathMHA);
+
     public slots:        
         void SLT_Load_RD_Ref();
         void SLT_Load_RD_Comp();        
@@ -132,6 +134,7 @@ public:
         void SLTM_ExportBatchReport();
 
         void SLTM_LoadProtonDoseSetFile();       
+		void SLTM_ConvertIBAOPG_Files();
 
 public:    
     QStringList m_strlistPath_RD_Original_Ref; //RD files, before the conversion
diff --git a/src/plastimatch/standalone/gamma_gui.ui b/src/plastimatch/standalone/gamma_gui.ui
index 99dcf39..baa3e91 100644
--- a/src/plastimatch/standalone/gamma_gui.ui
+++ b/src/plastimatch/standalone/gamma_gui.ui
@@ -1048,6 +1048,7 @@
      <string>Tool</string>
     </property>
     <addaction name="actionRename_RD_files"/>
+    <addaction name="actionConvert_IBA_OPG_files"/>
    </widget>
    <addaction name="menuFile"/>
    <addaction name="menuView"/>
@@ -1095,6 +1096,11 @@
     <string>Export Comp Profile as RFA300</string>
    </property>
   </action>
+  <action name="actionConvert_IBA_OPG_files">
+   <property name="text">
+    <string>Convert IBA OPG files</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <customwidgets>
@@ -1608,6 +1614,22 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>actionConvert_IBA_OPG_files</sender>
+   <signal>triggered()</signal>
+   <receiver>gamma_guiClass</receiver>
+   <slot>SLTM_ConvertIBAOPG_Files()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>604</x>
+     <y>430</y>
+    </hint>
+   </hints>
+  </connection>
  </connections>
  <slots>
   <slot>SLT_Load_RD_Ref()</slot>
@@ -1630,5 +1652,6 @@
   <slot>SLTM_ExportBatchReport()</slot>
   <slot>SLTM_LoadProtonDoseSetFile()</slot>
   <slot>SLTM_ExportCompProfileRFA300_ASC()</slot>
+  <slot>SLTM_ConvertIBAOPG_Files()</slot>
  </slots>
 </ui>
diff --git a/src/plastimatch/standalone/hnd_to_pfm.cxx b/src/plastimatch/standalone/hnd_to_pfm.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/opencl_probe.cxx b/src/plastimatch/standalone/opencl_probe.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/opencl_probe.h b/src/plastimatch/standalone/opencl_probe.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/qt_util.cxx b/src/plastimatch/standalone/qt_util.cxx
index 75e44d5..aa2acb4 100644
--- a/src/plastimatch/standalone/qt_util.cxx
+++ b/src/plastimatch/standalone/qt_util.cxx
@@ -17,7 +17,7 @@
 #include <QMessageBox>
 #include "itk_resample.h" //plm
 
-bool QUTIL::QPointF_Compare(QPointF& ptData1, QPointF& ptData2)
+bool QUTIL::QPointF_Compare(const QPointF& ptData1, const QPointF& ptData2)
 {
     //return (ptData1.x() > ptData2.x()); //ASCENDING
     return (ptData1.x() < ptData2.x()); //DESCENDING
diff --git a/src/plastimatch/standalone/qt_util.h b/src/plastimatch/standalone/qt_util.h
index c2d97f2..7f253c5 100644
--- a/src/plastimatch/standalone/qt_util.h
+++ b/src/plastimatch/standalone/qt_util.h
@@ -70,7 +70,7 @@ namespace QUTIL{
 
 
 //    typedef itk::ImageFileReader<FloatImageType> ReaderTypeYK;
-    bool QPointF_Compare(QPointF& ptData1, QPointF& ptData2);
+    bool QPointF_Compare(const QPointF& ptData1, const QPointF& ptData2);
 
     void ResampleFloatImg(FloatImageType::Pointer& spFloatInput, FloatImageType::Pointer& spFloatOutput, VEC3D& newSpacing);
 
diff --git a/src/plastimatch/standalone/shuffle_mha_main.cxx b/src/plastimatch/standalone/shuffle_mha_main.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/standalone/sobp_main.cxx b/src/plastimatch/standalone/sobp_main.cxx
index 3782b44..4ae518e 100644
--- a/src/plastimatch/standalone/sobp_main.cxx
+++ b/src/plastimatch/standalone/sobp_main.cxx
@@ -80,17 +80,17 @@ int main (int argc, char* argv[])
     {
         sscanf (argv[3], "%d", &Emin);
         sscanf (argv[4], "%d", &Emax);
-		mebs.set_energies(Emin, Emax);
+        mebs.set_energies(Emin, Emax);
     }
-	std::vector<float> weight;
-	std::vector<float> energy;
+    std::vector<float> weight;
+    std::vector<float> energy;
     mebs.optimizer(&weight, &energy);
-	for (int i = 0; i < energy.size(); i++)
-	{
-		mebs.add_peak(energy[i], mebs.get_spread(), weight[i]);
-	}
-	mebs.generate();
-	mebs.printparameters();
+    for (size_t i = 0; i < energy.size(); i++)
+    {
+        mebs.add_peak(energy[i], mebs.get_spread(), weight[i]);
+    }
+    mebs.generate();
+    mebs.printparameters();
 
     return 0;
 }
diff --git a/src/plastimatch/standalone/vf_invert_main.cxx b/src/plastimatch/standalone/vf_invert_main.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/CMakeLists.txt b/src/plastimatch/sys/CMakeLists.txt
index c0acc19..dbb1192 100644
--- a/src/plastimatch/sys/CMakeLists.txt
+++ b/src/plastimatch/sys/CMakeLists.txt
@@ -53,8 +53,9 @@ endforeach ()
 ##-----------------------------------------------------------------------------
 ##  LIBRARY DEPENDENCIES
 ##-----------------------------------------------------------------------------
-set (PLMSYS_LIBRARY_DEPENDENCIES 
-    )
+set (PLMSYS_LIBRARY_DEPENDENCIES
+  ${DLIB_LIBRARIES}
+  )
 if (LIBDL_FOUND)
     set (PLMSYS_LIBRARY_DEPENDENCIES
 	${PLMSYS_LIBRARY_DEPENDENCIES}
diff --git a/src/plastimatch/sys/compiler_warnings.h b/src/plastimatch/sys/compiler_warnings.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/dlib_threads.cxx b/src/plastimatch/sys/dlib_threads.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/dlib_threads.h b/src/plastimatch/sys/dlib_threads.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/logfile.cxx b/src/plastimatch/sys/logfile.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/plm_endian.cxx b/src/plastimatch/sys/plm_endian.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/plm_macros.h b/src/plastimatch/sys/plm_macros.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/plm_math.h b/src/plastimatch/sys/plm_math.h
old mode 100644
new mode 100755
index 3300f6a..318faca
--- a/src/plastimatch/sys/plm_math.h
+++ b/src/plastimatch/sys/plm_math.h
@@ -8,6 +8,7 @@
 #include <float.h>
 #include <math.h>
 #include <string.h>
+#include <limits>
 #include "compiler_warnings.h"
 
 #ifndef M_PI
@@ -103,11 +104,16 @@ static inline void vec4_copy (double* v1, const double* v2) {
     v1[0] = v2[0]; v1[1] = v2[1]; v1[2] = v2[2]; v1[3] = v2[3];
 }
 
-template<class T> static inline double 
+template<class T> static inline T
 vec3_dot (const T* v1, const T* v2) {
     return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
 }
 
+template<class T, class U> static inline float
+vec3_dot (const T* v1, const U* v2) {
+    return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
+}
+
 static inline double vec4_dot (const double* v1, const double* v2) {
     return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
 }
@@ -125,10 +131,17 @@ static inline void vec3_sub2 (double* v1, const double* v2) {
     v1[0] -= v2[0]; v1[1] -= v2[1]; v1[2] -= v2[2];
 }
 
+#if defined (commentout)
 template<class T> static inline void 
 vec3_sub3 (T* v1, const T* v2, const T* v3) {
     v1[0] = v2[0] - v3[0]; v1[1] = v2[1] - v3[1]; v1[2] = v2[2] - v3[2];
 }
+#endif
+
+template<class T, class U, class V> static inline void 
+vec3_sub3 (T* v1, const U* v2, const V* v3) {
+    v1[0] = v2[0] - v3[0]; v1[1] = v2[1] - v3[1]; v1[2] = v2[2] - v3[2];
+}
 
 static inline void vec3_invert (double* v1) {
     vec3_scale2 (v1, -1.0);
@@ -200,7 +213,7 @@ static inline void vec_outer (double* v1, const double* v2, const double* v3, co
 #define m_idx(m1,c,i,j) m1[i*c+j]
 
 /* v1 = m2 * v3 */
-static inline void mat43_mult_vec3 (double* v1, const double* m2, const double* v3) {
+static inline void mat43_mult_vec4 (double* v1, const double* m2, const double* v3) {
     v1[0] = vec4_dot(&m2[0], v3);
     v1[1] = vec4_dot(&m2[4], v3);
     v1[2] = vec4_dot(&m2[8], v3);
@@ -228,9 +241,18 @@ static inline void mat_mult_mat (
 /* 0 when value is NaN or infinity */
 static inline int is_number (const double x)
 {
+    // nan
     if (!(x == x)) return 0;
 
+    // inf
     if (x > DBL_MAX || x < -DBL_MAX) return 0;
+#if defined (commentout)
+    if (std::numeric_limits<double>::has_infinity &&
+        x == std::numeric_limits<double>::infinity())
+    {
+        return 0;
+    }
+#endif
 
     return 1;
 }
@@ -250,4 +272,7 @@ within_abs_tolerance (float value, float comp_value, float tolerance)
     return (fabsf (value - comp_value) <= tolerance);
 }
 
+#define NLMIN(T) (-std::numeric_limits<T>::max())
+#define NLMAX(T) std::numeric_limits<T>::max()
+
 #endif
diff --git a/src/plastimatch/sys/plm_return_code.h b/src/plastimatch/sys/plm_return_code.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/plm_sleep.cxx b/src/plastimatch/sys/plm_sleep.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/plm_sleep.h b/src/plastimatch/sys/plm_sleep.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/plm_timer.cxx b/src/plastimatch/sys/plm_timer.cxx
index d8fbcbb..9b2da1b 100644
--- a/src/plastimatch/sys/plm_timer.cxx
+++ b/src/plastimatch/sys/plm_timer.cxx
@@ -75,6 +75,13 @@ Plm_timer::stop ()
 }
 
 void
+Plm_timer::reset ()
+{
+    this->stop ();
+    d_ptr->acc_time = 0.;
+}
+
+void
 Plm_timer::resume ()
 {
     if (!d_ptr->running) {
diff --git a/src/plastimatch/sys/plm_timer.h b/src/plastimatch/sys/plm_timer.h
index d161735..c194d78 100644
--- a/src/plastimatch/sys/plm_timer.h
+++ b/src/plastimatch/sys/plm_timer.h
@@ -15,6 +15,7 @@ public:
 
     void start ();
     void stop ();
+    void reset ();
     void resume ();
     double report ();
 private:
diff --git a/src/plastimatch/sys/smart_pointer.h b/src/plastimatch/sys/smart_pointer.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/sys/string_util.cxx b/src/plastimatch/sys/string_util.cxx
old mode 100755
new mode 100644
index 3f7fc67..c827be2
--- a/src/plastimatch/sys/string_util.cxx
+++ b/src/plastimatch/sys/string_util.cxx
@@ -418,23 +418,52 @@ std::vector<std::string> string_split (
     return elems;
 }
 
-bool split_tag_val (
+bool
+split_key_val (
     const std::string& s, 
-    std::string& tag,
+    std::string& key,
     std::string& val,
     char delim)
 {
     size_t loc = s.find (delim);
     if (loc == std::string::npos) {
-        tag = "";
+        key = string_trim (s);
         val = "";
         return false;
     }
-    tag = string_trim (s.substr (0, loc));
+    key = string_trim (s.substr (0, loc));
     val = string_trim (s.substr (loc + 1));
     return true;
 }
 
+bool
+split_array_index (
+    const std::string& s, 
+    std::string& array, 
+    std::string& index)
+{
+    size_t start_loc = s.find ('[');
+    size_t end_loc = s.find (']');
+    if (start_loc == std::string::npos
+        && end_loc == std::string::npos)
+    {
+        array = string_trim (s);
+        index = "";
+        return true;
+    }
+    if (start_loc != std::string::npos
+        && end_loc != std::string::npos
+        && end_loc > start_loc + 1)
+    {
+        array = string_trim (s.substr (0, start_loc));
+        index = string_trim (s.substr (start_loc + 1, end_loc - start_loc - 1));
+        return true;
+    }
+    array = string_trim (s);
+    index = "";
+    return false;
+}
+
 /* Explicit instantiations */
 template PLMSYS_API std::string PLM_to_string(int value);
 template PLMSYS_API std::string PLM_to_string(size_t value);
diff --git a/src/plastimatch/sys/string_util.h b/src/plastimatch/sys/string_util.h
index 18ed22d..e70e43c 100644
--- a/src/plastimatch/sys/string_util.h
+++ b/src/plastimatch/sys/string_util.h
@@ -50,7 +50,9 @@ template <typename T> PLMSYS_API std::string PLM_to_string(T *value, int n);
 
 PLMSYS_API std::vector<std::string>& string_split (const std::string &s, char delim, std::vector<std::string> &elems);
 PLMSYS_API std::vector<std::string> string_split (const std::string &s, char delim);
-PLMSYS_API bool split_tag_val (const std::string& s, 
-    std::string& tag, std::string& val, char delim = '=');
+PLMSYS_API bool split_key_val (const std::string& s, 
+    std::string& key, std::string& val, char delim = '=');
+PLMSYS_API bool split_array_index (const std::string& s, 
+    std::string& array, std::string& index);
 
 #endif
diff --git a/src/plastimatch/test/api_test.cxx b/src/plastimatch/test/api_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/cpp_eps_test.cxx b/src/plastimatch/test/cpp_eps_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/cpp_limits_test.cxx b/src/plastimatch/test/cpp_limits_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/cpp_overflow_test.cxx b/src/plastimatch/test/cpp_overflow_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/cpp_sizeof_test.cxx b/src/plastimatch/test/cpp_sizeof_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/cpp_template_test.cxx b/src/plastimatch/test/cpp_template_test.cxx
old mode 100755
new mode 100644
index b834995..7c47bd4
--- a/src/plastimatch/test/cpp_template_test.cxx
+++ b/src/plastimatch/test/cpp_template_test.cxx
@@ -1,5 +1,6 @@
 #include <stdio.h>
-
+#include <map>
+#include <string>
 
 /* Simple test */
 typedef void (*B) (int);
@@ -51,6 +52,17 @@ template < template<class J> class I > void l (J x) {
 }
 #endif
 
+/* This is an example inheriting from std::map */
+/* Cf. http://stackoverflow.com/questions/10477839/c-inheriting-from-stdmap 
+   (The answer from Emilio Garavaglia, not the others) */
+template <class L> class M : public std::map<std::string,L>
+{
+public:
+    typename std::map<std::string,L>::iterator get_default (std::string s) {
+        return this->begin();
+    }
+};
+
 int main 
 (
     int argc,
@@ -63,4 +75,7 @@ int main
     d< G<int> >(x);
     h< int, G >(x);
     k< G, int >(x);
+
+    M<int> m;
+    M<int>::iterator mit = m.get_default("FOO");
 }
diff --git a/src/plastimatch/test/cuda/cuda_test.cu b/src/plastimatch/test/cuda/cuda_test.cu
index 8eff5fc..7d1b73f 100644
--- a/src/plastimatch/test/cuda/cuda_test.cu
+++ b/src/plastimatch/test/cuda/cuda_test.cu
@@ -4,6 +4,18 @@
 // Simple utility function to check for CUDA runtime errors
 void checkCUDAError (const char *msg);
 
+class A {
+public:
+    int a;
+    float b;
+public:
+    int get_a ();
+    void set_a (int val);
+};
+
+int A::get_a () { return this->a; }
+void A::set_a (int val) { this->a = val; }
+
 // Part 3 of 5: implement the kernel
 __global__ void 
 myFirstKernel(int *d_a)
@@ -136,6 +148,11 @@ cuda_mem_test (int argc, char** argv)
 int 
 main (int argc, char** argv)
 {
-    //cuda_test_1 (argc, argv);
+    // do some c++ here
+    A a1;
+    a1.set_a (32);
+    printf ("C++ test: %d\n", a1.get_a());
+
+    // cuda_test_1 (argc, argv);
     return cuda_mem_test (argc, argv);
 }
diff --git a/src/plastimatch/test/dcmtk_test.cxx b/src/plastimatch/test/dcmtk_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/dlib_test.cxx b/src/plastimatch/test/dlib_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/dlib_thread_test.cxx b/src/plastimatch/test/dlib_thread_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/gabor_test.cxx b/src/plastimatch/test/gabor_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/itk_test.cxx b/src/plastimatch/test/itk_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/itk_test_directions.cxx b/src/plastimatch/test/itk_test_directions.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/itk_thread_test.cxx b/src/plastimatch/test/itk_thread_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/libyaml_test.cxx b/src/plastimatch/test/libyaml_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/plm_restart_test.cxx b/src/plastimatch/test/plm_restart_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/rapidjson_test.cxx b/src/plastimatch/test/rapidjson_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/rtplan_test.cxx b/src/plastimatch/test/rtplan_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/smartp_test_i.cxx b/src/plastimatch/test/smartp_test_i.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/smartp_test_ii.cxx b/src/plastimatch/test/smartp_test_ii.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/test/yamlcpp_test.cxx b/src/plastimatch/test/yamlcpp_test.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/CMakeLists.txt b/src/plastimatch/util/CMakeLists.txt
index 818b33d..c447de0 100644
--- a/src/plastimatch/util/CMakeLists.txt
+++ b/src/plastimatch/util/CMakeLists.txt
@@ -26,7 +26,7 @@ set (PLMUTIL_LIBRARY_SRC
   hausdorff_distance.cxx hausdorff_distance.h 
   image_boundary.cxx image_boundary.h
   image_center.cxx image_center.h
-  itk_adjust.cxx
+  itk_adjust.cxx itk_adjust.h 
   itk_distance_map.cxx
   itk_crop.cxx
   itk_gabor.cxx
@@ -38,13 +38,14 @@ set (PLMUTIL_LIBRARY_SRC
   proj_image_filter.cxx
   plm_series.cxx
   plm_study.cxx
-  rt_study_warp.cxx rt_study_warp.h 
+  rt_study_warp.cxx rt_study_warp.h
   sift.cxx
   simplify_points.cxx 
   ss_img_stats.cxx 
   synthetic_mha.cxx
   synthetic_vf.cxx
   threshbox.cxx
+  volume_adjust.cxx volume_adjust.h
   vf_invert.cxx
   )
 if (FFTW_FOUND)
diff --git a/src/plastimatch/util/dicom_sro_save.cxx b/src/plastimatch/util/dicom_sro_save.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/dicom_sro_save.h b/src/plastimatch/util/dicom_sro_save.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/distance_map.cxx b/src/plastimatch/util/distance_map.cxx
old mode 100755
new mode 100644
index c458860..769830a
--- a/src/plastimatch/util/distance_map.cxx
+++ b/src/plastimatch/util/distance_map.cxx
@@ -23,12 +23,15 @@ public:
         use_squared_distance = false;
         maximum_distance = FLT_MAX;
         algorithm = Distance_map::DANIELSSON;
+        vbb = ADAPTIVE_PADDING;
     }
 public:
     Distance_map::Algorithm algorithm;
     bool inside_is_positive;
     bool use_squared_distance;
     float maximum_distance;
+    Volume_boundary_behavior vbb;
+
     UCharImageType::Pointer input;
     FloatImageType::Pointer output;
 public:
@@ -221,7 +224,12 @@ Distance_map_private::run_native_danielsson ()
 {
     /* Compute boundary of image
        vb = volume of boundary, imgb = img of boundary */
-    Plm_image pib (do_image_boundary (this->input));
+    Image_boundary ib;
+    ib.set_volume_boundary_behavior (vbb);
+    ib.set_input_image (this->input);
+    ib.run ();
+    UCharImageType::Pointer itk_ib = ib.get_output_image ();
+    Plm_image pib (itk_ib);
     Volume::Pointer vb = pib.get_volume_uchar();
     unsigned char *imgb = (unsigned char*) vb->img;
 
@@ -251,9 +259,6 @@ Distance_map_private::run_native_danielsson ()
         vb->spacing[2] * vb->spacing[2]
     };
 
-    /* GCS FIX -- This is only implemented as distance to set, 
-       not distance to boundary. */
-
     /* GCS FIX -- I'm not entirely sure if it is required to scan 
        both forward and backward for j direction.  Need to test. */
 
@@ -403,6 +408,13 @@ Distance_map::set_input_image (UCharImageType::Pointer image)
     d_ptr->input = image;
 }
 
+void
+Distance_map::set_input_image (const Plm_image::Pointer& image)
+{
+    Plm_image::Pointer pi_clone = image->clone ();
+    d_ptr->input = pi_clone->itk_uchar ();
+}
+
 void 
 Distance_map::set_use_squared_distance (bool use_squared_distance)
 {
@@ -415,6 +427,12 @@ Distance_map::set_maximum_distance (float maximum_distance)
     d_ptr->maximum_distance = maximum_distance;
 }
 
+void
+Distance_map::set_volume_boundary_behavior (Volume_boundary_behavior vbb)
+{
+    d_ptr->vbb = vbb;
+}
+
 void 
 Distance_map::set_inside_is_positive (bool inside_is_positive)
 {
diff --git a/src/plastimatch/util/distance_map.h b/src/plastimatch/util/distance_map.h
old mode 100755
new mode 100644
index 2b6c884..228e09a
--- a/src/plastimatch/util/distance_map.h
+++ b/src/plastimatch/util/distance_map.h
@@ -6,6 +6,8 @@
 
 #include "plmutil_config.h"
 #include "itk_image_type.h"
+#include "plm_image.h"
+#include "volume_boundary_behavior.h"
 
 class Distance_map_private;
 class Plm_image;
@@ -34,6 +36,8 @@ public:
     void set_input_image (const char* image_fn);
     /*! \brief Set the input image as an ITK image. */
     void set_input_image (const UCharImageType::Pointer image);
+    /*! \brief Set the input image as a Plm_image. */
+    void set_input_image (const Plm_image::Pointer& image);
     /*! \brief Choose whether the output image is distance or squared 
       distance. The default is not squared distance. */
     void set_use_squared_distance (bool use_squared_distance);
@@ -44,6 +48,9 @@ public:
     void set_algorithm (const std::string& algorithm);
     /*! \brief Set maximum distance */
     void set_maximum_distance (float max_distance);
+    /*! \brief Set the volume boundary behavior, either 
+      ZERO_PADDING, EDGE_PADDING, or ADAPTIVE_PADDING */
+    void set_volume_boundary_behavior (Volume_boundary_behavior vbb);
     ///@}
 
     /*! \name Execution */
diff --git a/src/plastimatch/util/gabor.cxx b/src/plastimatch/util/gabor.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/gabor.h b/src/plastimatch/util/gabor.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/hausdorff_distance.cxx b/src/plastimatch/util/hausdorff_distance.cxx
index d399d13..a3b1f24 100644
--- a/src/plastimatch/util/hausdorff_distance.cxx
+++ b/src/plastimatch/util/hausdorff_distance.cxx
@@ -13,6 +13,7 @@
 #include "hausdorff_distance.h"
 #include "image_boundary.h"
 #include "itk_image_load.h"
+#include "itk_image_save.h"
 #include "itk_resample.h"
 #include "logfile.h"
 #include "plm_image.h"
@@ -25,6 +26,7 @@ public:
         pct_hausdorff_distance_fraction = 0.95;
         dmap_alg = "";
         maximum_distance = FLT_MAX;
+        vbb = ADAPTIVE_PADDING;
         this->clear_statistics ();
     }
 public:
@@ -51,6 +53,7 @@ public:
 
     std::string dmap_alg;
     float maximum_distance;
+    Volume_boundary_behavior vbb;
 
     UCharImageType::Pointer ref_image;
     UCharImageType::Pointer cmp_image;
@@ -111,6 +114,12 @@ Hausdorff_distance::set_maximum_distance (float maximum_distance)
     d_ptr->maximum_distance = maximum_distance;
 }
 
+void
+Hausdorff_distance::set_volume_boundary_behavior (Volume_boundary_behavior vbb)
+{
+    d_ptr->vbb = vbb;
+}
+
 void 
 Hausdorff_distance::run_internal (
     UCharImageType::Pointer image1,
@@ -124,6 +133,7 @@ Hausdorff_distance::run_internal (
     dmap_filter.set_inside_is_positive (false);
     dmap_filter.set_use_squared_distance (false);
     dmap_filter.set_maximum_distance (d_ptr->maximum_distance);
+    dmap_filter.set_volume_boundary_behavior (d_ptr->vbb);
     dmap_filter.run ();
     FloatImageType::Pointer dmap = dmap_filter.get_output_image ();
 
@@ -137,10 +147,11 @@ Hausdorff_distance::run_internal (
 
     /* Find boundary pixels */
     Image_boundary ib;
+    ib.set_volume_boundary_behavior (d_ptr->vbb);
     ib.set_input_image (image1);
     ib.run ();
     UCharImageType::Pointer itk_ib = ib.get_output_image ();
-
+    
     /* Convert to plm_image */
     Plm_image pli_ib (itk_ib);
     Volume::Pointer vol_ib = pli_ib.get_volume_uchar ();
diff --git a/src/plastimatch/util/hausdorff_distance.h b/src/plastimatch/util/hausdorff_distance.h
index 7105704..d33aa19 100644
--- a/src/plastimatch/util/hausdorff_distance.h
+++ b/src/plastimatch/util/hausdorff_distance.h
@@ -6,6 +6,7 @@
 
 #include "plmutil_config.h"
 #include "itk_image.h"
+#include "volume_boundary_behavior.h"
 
 class Plm_image;
 class Hausdorff_distance_private;
@@ -120,6 +121,9 @@ public:
     /*! \brief Choose the maximum distance that is returned when 
       computing the distance map */
     void set_maximum_distance (float maximum_distance);
+    /*! \brief Set the volume boundary behavior, either 
+      ZERO_PADDING, EDGE_PADDING, or ADAPTIVE_PADDING */
+    void set_volume_boundary_behavior (Volume_boundary_behavior vbb);
     ///@}
 
     /*! \name Execution */
diff --git a/src/plastimatch/util/image_boundary.cxx b/src/plastimatch/util/image_boundary.cxx
old mode 100755
new mode 100644
index 038b623..b85cd78
--- a/src/plastimatch/util/image_boundary.cxx
+++ b/src/plastimatch/util/image_boundary.cxx
@@ -13,17 +13,17 @@
 #include "plm_image.h"
 #include "plm_image_header.h"
 #include "volume.h"
+#include "volume_boundary_behavior.h"
 
 class Image_boundary_private {
 public:
     Image_boundary_private () {
-        vbb = Image_boundary::EDGE_PADDING;
-//        vbb = Image_boundary::ZERO_PADDING;
+        vbb = ADAPTIVE_PADDING;
     }
 public:
     UCharImageType::Pointer input_image;
     UCharImageType::Pointer output_image;
-    Image_boundary::Volume_boundary_behavior vbb;
+    Volume_boundary_behavior vbb;
 public:
     void run ();
 protected:
@@ -77,6 +77,28 @@ protected:
             return 0;
         }
 
+        return 0;
+    }
+
+    unsigned char classify_ap (
+        const Volume::Pointer& vol_in,
+        const unsigned char *img_in,
+        plm_long i, plm_long j, plm_long k, plm_long v)
+    {
+        /* If not inside volume, then not on boundary */
+        if (!img_in[v]) {
+            return 0;
+        }
+
+        /* Check for non-zero edge pixels; these are boundary if 
+           dimension > 1 */
+        if (vol_in->dim[2] > 1 && (k == 0 || k == vol_in->dim[2]-1)
+            || vol_in->dim[1] > 1 && (j == 0 || j == vol_in->dim[1]-1)
+            || vol_in->dim[0] > 1 && (i == 0 || i == vol_in->dim[0]-1))
+        {
+            return 1;
+        }
+
         /* Look for neighboring zero voxel in six-neighborhood,
            ignoring voxels beyond boundary */
         if (i != 0 
@@ -130,10 +152,17 @@ Image_boundary_private::run ()
     for (plm_long k = 0, v = 0; k < vol_in->dim[2]; k++) {
         for (plm_long j = 0; j < vol_in->dim[1]; j++) {
             for (plm_long i = 0; i < vol_in->dim[0]; i++, v++) {
-                if (this->vbb == Image_boundary::ZERO_PADDING) {
+                switch (this->vbb) {
+                case ZERO_PADDING:
                     img_out[v] = classify_zp (vol_in, img_in, i, j, k, v);
-                } else {
+                    break;
+                case EDGE_PADDING:
                     img_out[v] = classify_ep (vol_in, img_in, i, j, k, v);
+                    break;
+                case ADAPTIVE_PADDING:
+                default:
+                    img_out[v] = classify_ap (vol_in, img_in, i, j, k, v);
+                    break;
                 }
             }
         }
@@ -166,6 +195,12 @@ Image_boundary::set_input_image (
     d_ptr->input_image = image;
 }
 
+void
+Image_boundary::set_volume_boundary_behavior (Volume_boundary_behavior vbb)
+{
+    d_ptr->vbb = vbb;
+}
+
 void 
 Image_boundary::run ()
 {
diff --git a/src/plastimatch/util/image_boundary.h b/src/plastimatch/util/image_boundary.h
old mode 100755
new mode 100644
index f4551ce..b5af804
--- a/src/plastimatch/util/image_boundary.h
+++ b/src/plastimatch/util/image_boundary.h
@@ -6,6 +6,7 @@
 
 #include "plmutil_config.h"
 #include "itk_image.h"
+#include "volume_boundary_behavior.h"
 
 class Plm_image;
 class Image_boundary_private;
@@ -25,18 +26,6 @@ public:
     Image_boundary_private *d_ptr;
 
 public:
-    /*! \brief This enum is used to control the algorithm behavior 
-      for voxels at the edge of the volume.  If ZERO_PADDING is 
-      specified, all non-zero voxels at the edge of the volume 
-      will be treated as boundary voxels.  If EDGE_PADDING is 
-      specified, non-zero voxels at the edge of the volume are 
-      only treated as boundary voxels if they neighbor 
-      a zero voxel. */
-    enum Volume_boundary_behavior {
-        ZERO_PADDING,
-        EDGE_PADDING
-    };
-public:
 
     /*! \name Inputs */
     ///@{
@@ -46,7 +35,7 @@ public:
     /*! \brief Set the input image as an ITK image. */
     void set_input_image (const UCharImageType::Pointer image);
     /*! \brief Set the volume boundary behavior, either 
-      ZERO_PADDING or EDGE_PADDING */
+      ZERO_PADDING, EDGE_PADDING, or ADAPTIVE_PADDING */
     void set_volume_boundary_behavior (Volume_boundary_behavior vbb);
     ///@}
 
diff --git a/src/plastimatch/util/image_center.cxx b/src/plastimatch/util/image_center.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/image_center.h b/src/plastimatch/util/image_center.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/itk_adjust.cxx b/src/plastimatch/util/itk_adjust.cxx
old mode 100755
new mode 100644
index df92b01..a564cd4
--- a/src/plastimatch/util/itk_adjust.cxx
+++ b/src/plastimatch/util/itk_adjust.cxx
@@ -28,79 +28,6 @@ itk_adjust (FloatImageType::Pointer image_in, const Float_pair_list& al)
         it.Set (pwlut.lookup (it.Get()));
     }
     return image_out;
-
-#if defined (commentout)
-    /* Special processing for end caps */
-    float left_slope = 1.0;
-    float right_slope = 1.0;
-    Float_pair_list::const_iterator ait_start = al.begin();
-    Float_pair_list::const_iterator ait_end = al.end();
-    if (ait_start->first == -std::numeric_limits<float>::max()) {
-        left_slope = ait_start->second;
-        ait_start++;
-    }
-    if ((--ait_end)->first == std::numeric_limits<float>::max()) {
-        right_slope = ait_end->second;
-        --ait_end;
-    }
-
-    /* Debug adjustment lists */
-    Float_pair_list::const_iterator it_d = ait_start;
-#if defined (commentout)
-    while (it_d != ait_end) {
-        printf ("[%f,%f]\n", it_d->first, it_d->second);
-        it_d ++;
-    }
-    printf ("[%f,%f]\n", it_d->first, it_d->second);
-    printf ("slopes [%f,%f]\n", left_slope, right_slope);
-    printf ("ait_start [%f,%f]\n", ait_start->first, ait_start->second);
-    printf ("ait_end [%f,%f]\n", ait_end->first, ait_end->second);
-#endif
-    
-    for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
-        float vin = it.Get();
-        float vout;
-
-        /* Three possible cases: before first node, between two nodes, and 
-           after last node */
-
-        /* Case 1 */
-        if (vin <= ait_start->first) {
-            vout = ait_start->second + (vin - ait_start->first) * left_slope;
-#if defined (commentout)
-            printf ("[1] < %f (%f -> %f)\n", ait_start->first, vin, vout);
-#endif
-            goto found_vout;
-        }
-        else if (ait_start != ait_end) {
-            Float_pair_list::const_iterator ait = ait_start;
-            Float_pair_list::const_iterator prev = ait_start;
-            do {
-                ait++;
-                /* Case 2 */
-                if (vin <= ait->first) {
-                    float slope = (ait->second - prev->second) 
-                        / (ait->first - prev->first);
-                    vout = prev->second + (vin - prev->first) * slope;
-#if defined (commentout)
-                    printf ("[2] in (%f,%f) (%f -> %f)\n", prev->first, 
-                        ait->first, vin, vout);
-#endif
-                    goto found_vout;
-                }
-                prev = ait;
-            } while (ait != ait_end);
-        }
-        /* Case 3 */
-        vout = ait_end->second + (vin - ait_end->first) * right_slope;
-#if defined (commentout)
-        printf ("[3] > %f (%f -> %f)\n", ait_end->first, vin, vout);
-#endif
-    found_vout:
-        it.Set (vout);
-    }
-    return image_out;
-#endif
 }
 
 FloatImageType::Pointer
diff --git a/src/plastimatch/util/itk_distance_map.cxx b/src/plastimatch/util/itk_distance_map.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/itk_threshold.cxx b/src/plastimatch/util/itk_threshold.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/itk_threshold.h b/src/plastimatch/util/itk_threshold.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/vf_invert.cxx b/src/plastimatch/util/vf_invert.cxx
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/vf_invert.h b/src/plastimatch/util/vf_invert.h
old mode 100755
new mode 100644
diff --git a/src/plastimatch/util/volume_adjust.cxx b/src/plastimatch/util/volume_adjust.cxx
new file mode 100644
index 0000000..67b70a8
--- /dev/null
+++ b/src/plastimatch/util/volume_adjust.cxx
@@ -0,0 +1,40 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#include "plmutil_config.h"
+#include <limits>
+
+#include "float_pair_list.h"
+#include "plm_math.h"
+#include "print_and_exit.h"
+#include "pwlut.h"
+#include "volume.h"
+#include "volume_adjust.h"
+
+Volume::Pointer
+volume_adjust (const Volume::Pointer& image_in, const Float_pair_list& al)
+{
+    Volume::Pointer vol_out = image_in->clone (PT_FLOAT);
+    float *vol_img = vol_out->get_raw<float> ();
+    
+    Pwlut pwlut;
+    pwlut.set_lut (al);
+
+    for (plm_long v = 0; v < vol_out->npix; v++) {
+        vol_img[v] = pwlut.lookup (vol_img[v]);
+    }
+    return vol_out;
+}
+
+Volume::Pointer
+volume_adjust (const Volume::Pointer& image_in, const std::string& adj_string)
+{
+    Float_pair_list al = parse_float_pairs (adj_string);
+
+    if (al.empty()) {
+        print_and_exit ("Error: couldn't parse adjust string: %s\n",
+            adj_string.c_str());
+    }
+
+    return volume_adjust (image_in, al);
+}
diff --git a/src/plastimatch/util/volume_adjust.h b/src/plastimatch/util/volume_adjust.h
new file mode 100644
index 0000000..2376093
--- /dev/null
+++ b/src/plastimatch/util/volume_adjust.h
@@ -0,0 +1,15 @@
+/* -----------------------------------------------------------------------
+   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
+   ----------------------------------------------------------------------- */
+#ifndef _volume_adjust_h_
+#define _volume_adjust_h_
+
+#include "plmutil_config.h"
+#include "float_pair_list.h"
+
+PLMUTIL_API Volume::Pointer
+volume_adjust (const Volume::Pointer& image_in, const Float_pair_list& al);
+PLMUTIL_API Volume::Pointer
+volume_adjust (const Volume::Pointer& image_in, const std::string& adj_string);
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/plastimatch.git



More information about the debian-med-commit mailing list