******************************************************************************
Structure to structure registration

moving[1]


******************************************************************************
ITK Demons

Deep dive Part I: demons_insight impl
-------------------------------------
LDDemRFwME : LDDefRF
  Set DemonsRegistrationFunctionType to ESMDemonsRegistrationWithMaskFunction
  Add methods GetMaskImage, SetMaskImage

SLDDRFwME : LDDefRF
  Set DemonsRegistrationFunctionType to ESMDemonsRegistrationWithMaskFunction
  Add methods GetMaskImage, SetMaskImage

LDDefRF : PDEDRwMF
  No other mention of masks

DDRwMF : PDEDRwMF
  Set DemonsRegistrationFunctionType to ESMDemonsRegistrationWithMaskFunction
  Add methods GetMaskImage, SetMaskImage

FSFDRwMF : PDEDRwMF
  Set DemonsRegistrationFunctionType to ESMDemonsRegistrationWithMaskFunction

PDEDRwMF : DenseFiniteDifferenceImageFilter
  Add methods SetMovingMaskImage, SetFixedMaskImage but these are not implemented

ESMDRwMFu : PDEDRFu
  Add methods GetMaskImage, SetMaskImage
  Implement masking


Deep dive Part II: ITK v4 impl
------------------------------
CRFu : PDEDRFu
DRFu : PDEDRFu
ESMDRFu : PDEDRFu
FSFDRfu : PDEDRFu
LSMRFu : PDEDRFu
SFDRFu : PDEDRFu
PDEDRFu : (not copied)

CRF : PDEDRF
  Templated RegistrationFunctionType; organized slightly differently
DRF : PDEDRF
  Uses DRFu
DDRF : PDEDRF
  Uses EMSDRFu
FSFDRF : PDEDRF
  Uses EMSDRFu
LSMRF : PDEDRF
  Uses LSMRFu
SFDRF : PDEDRF
  Uses SFDRFu
PDEDRF : DenseFiniteDifferenceImageFilter

LDDRF : LDDefRF
  Uses ESMDRF
SLDDRF : LDDefRF
  Uses ESMDRF
LDDefRF : DenseFiniteDifferenceImageFilter
  Uses PDEDRF


Strategy to fix
---------------
PDEDRFu
  Do nothing at this time
ESMDRwMFu : PDEDRFu
  Add methods GetMaskImage, SetMaskImage
  Implement masking
  Don't include functions that are not overridden

PDEDRwMF : PDEDRF
  Add GetMetric()
  Add SetMovingMaskImage, SetFixedMaskImage
DDRwMF : PDEDRwMF
  Uses EMSDRwMFu
  Don't include functions that are not overridden
FSFDRwMF : PDEDRwMF
  Uses EMSDRwMFu
  Don't include functions that are not overridden

LDDefRF : PDEDRwMF
  Nothing else changes
LDDRwMF : LDDefRF
  Uses EMSDRwMFu
  Add methods GetMaskImage, SetMaskImage
  Don't include functions that are not overridden
SLDDRwMF : LDDefRF
  Uses EMSDRwMFu
  Add methods GetMaskImage, SetMaskImage
  Don't include functions that are not overridden


******************************************************************************
DRR, WED, BSTV = beam specific target volume

DRR pro
-------
Drr uses command line options

DRR con
-------
Drr does not use IEC
Wed maintains an actual wed volume
Drr does not have programmable LUT


******************************************************************************
Dose calc notes #4

Deep dive (priority 1, n/a, no test)
------------------------------------
Plan_calc::compute_beam_dose
 Beam_calc::prepare_for_calc
 for each energy
   compute_dose_{a,b,d}

Beam_calc::prepare_for_calc
 Beam_calc::compute_beam_data_from_target
  Beam_calc::compute_beam_modifiers_passive_scattering_b
   Beam_calc::compute_beam_modifiers
    Beam_calc::compute_target_wepl_min_max
    Beam_calc::apply_smearing_to_target
   Rt_mebs::set_prescription_depths
    Rt_mebs::update_energies_from_prescription
   Rpl_volume::apply_beam_modifiers
   Beam_calc::compute_beam_data_from_prescription
    Rt_mebs::optimize_sobp
    Beam_calc::compute_beam_data_from_manual_peaks
     Rt_mebs::generate_part_num_from_weight
     // compute_beam_modifiers not re-run

Deep dive (priority 5, passive target, test 4d)
-----------------------------------------------
Plan_calc::compute_beam_dose
 Beam_calc::prepare_for_calc
 for each energy
   compute_dose_{a,b,d}

Beam_calc::prepare_for_calc
 Beam_calc::compute_beam_data_from_target
  Beam_calc::compute_beam_modifiers_passive_scattering_b
   Beam_calc::compute_beam_modifiers
    Beam_calc::compute_target_wepl_min_max
    Beam_calc::apply_smearing_to_target
   Rt_mebs::set_prescription_depths
    Rt_mebs::update_energies_from_prescription
   Rpl_volume::apply_beam_modifiers
   Beam_calc::compute_beam_data_from_prescription
    Rt_mebs::optimize_sobp
    Beam_calc::compute_beam_data_from_manual_peaks
     Rt_mebs::generate_part_num_from_weight
     // compute_beam_modifiers not re-run

******************************************************************************
Dose calc notes #3

Command file
------------
Overrides for any beam model parameter

Beam model
----------
Allowed energies (min/max/res or list)
Depth dose for each energy (analytic parameters or files)
Field size
Beamlet spacing
Beamline type
Allowed spot positions
Spot sigma
Source distance
Aperture distance
Flavor/homo approx/ray step


******************************************************************************
Dose calc notes #2

(A1) Aperture
(A2) Range compensator
(B1) Allowed energies (e.g. energy res)
(B2) Energy min/max
(B3) Energy weights (passive)
(C) Target
(D1) Spot map
(D2) Beamlet map

What combinations are acceptable?

D alone
D + A
C alone
C + A
C + B
B + A
B alone

To wit:

A is a modifier, can be added to anything
D defines B
C may be used to compute A and/or B through optimization
What about manually specified energy weights?

A possible strategy

1) Evaluate which items (A-E) need computed
2) Optimize (A,B) from (C)
3) Create MEBS structure
4) Optimize (D) from (A,B,C)


******************************************************************************
Dose calc notes

Rt_mebs
  - add_peak()
    - Create depth dose curve (ensuring all curves have same start/stop)
    - Appends to depth_dose
    - Appends to depth_dose_weight
    - Appends to energies
  - generate() seems to add together several pristine peaks, stored in
    the depth_dose array, and put the results into e_lut and f_lut.
    It is only used in the sobp_main() standalone.
  - add_peak() is called from:
    - Beam_calc::compute_default_beam()
    - Rt_parms::append_peak() -- while interpreting [PEAK] sections
    - Rt_mebs::optimize_sobp()
    - Rt_mebs::load_beamlet_map()
    - Rt_mebs::compute_particle_number_matrix_from_target_active()
Rt_depth_dose
  - lookup_energy() gets an interpolated value from the lut

Overview of beam preparation tasks

- Beam_calc::prepare_for_calc 
  (1) Beam_calc::compute_beam_data_from_beamlet_map
    - Rt_mebs::load_beamlet_map
  (2) Beam_calc::compute_beam_data_from_spot_map
    - Rt_mebs::set_from_spot_map
  (3) Beam_calc::compute_beam_data_from_manual_peaks
    - Beam_calc::compute_beam_modifiers_active_scanning
  (4) Beam_calc::compute_beam_data_from_prescription
    - Beam_calc::compute_beam_modifiers_active_scanning
  (5) Beam_calc::compute_beam_data_from_target
    (5a) Beam_calc::compute_beam_data_from_prescription
    (5b) Beam_calc::compute_beam_modifiers_active_scanning
           Beam_calc::compute_beam_modifiers_core
         Rt_mebs::compute_particle_number_matrix_from_target_active
  (6) Beam_calc::compute_default_beam


******************************************************************************
B-spline mismatch

Bug #32 is caused by a mismatch in the way B-spline grid geometry is
computed for ITK and native data structures.

Ideally, we can move to a form where native data structures are
deprecated in favor of wrapped ITK data structures (ITK for standard
stuff + additional info used in native algorithms).  But as a pathway
toward that, we should unify the method for computing B-spline grid size.

As of 1.7.2.1, native algorihm uses the following:
  create_gpuit_bxf (pih, grid_spac)
  -> compute vox per region
  -> initialize
     -> convert vpr to grid spacing and rdim/cdim

And the itk algorithm uses the following:
  bsp_grid_from_img_grid
  -> compute cdim from image extent and (above computed)

The code in xform_any_to_gpuit_bsp mixes these paradigms.  Currently,
the only way to convert from arbitrary type to itk_bsp does not
have capability to clone geometry from bxf.
  xform_any_to_gpuit_bsp
  -> create_gpuit_bxf (pih, grid_spac)
     -> compute vox per region
     -> initialize
        -> convert vpr to grid spacing and rdim/cdim
  -> xform_any_to_itk_bsp_nobulk
     -> xform_any_to_itk_bsp_nobulk
        -> itk_bsp_set_grid_img
           -> bsp_grid_from_img_grid
        -> bsp_grid_from_img_grid (why is this called twice?)

So the proposed change is:

  a) Compute desired bsp geometry
     -> Bspline_header::set() does this now (?)
     	class of Bspline_xform
  b) Convert to itk_bsp using the computed geometry
     -> This function would take a Bspline_xform (or Bspline_header if
     	it exists)
  c) Convert itk_bsp to bxf

The following functions have somewhat overlapping purpose

xform::itk_bsp_set_grid
  Sets grid geometry parameters (origin, spacing, etc) without any interal
  processing; allocates and initializes itk parameter buffer
bsp_grid_from_img_grid
  Uses pih and grid_spacing to set itk grid geometry parameters
itk_bsp_set_grid_img
  Calls bsp_grid_from_img_grid to get the itk grid geometry, then calls
  itk_bsp_set_grid to initialize itk_bsp
gpuit_bsp_grid_to_itk_bsp_grid
  Copies/converts bxf geometry to itk geometry
gpuit_bsp_to_itk_bsp_raw
  Calls gpuit_bsp_grid_to_itk_bsp_grid, creates itk bsp, calls
  xform::itk_bsp_set_grid to set itk_bsp geometry, then copies coefficients
  to itk parameter array
xform_gpuit_bsp_to_itk_bsp
  If grid spacing is sent, call gpuit_bsp_to_itk_bsp_raw to convert to
  itk_bsp, then call xform_itk_bsp_to_itk_bsp to resample

******************************************************************************
CUDA Wraping, existing version

#define plmcuda_EXPORT(f, ...)                 \
    f (__VA_ARGS__); typedef f##_t(__VA_ARGS__);

#define DELAYLOAD_WRAP(f, ...)                 \
    f (__VA_ARGS__); typedef f##_t(__VA_ARGS__);

#define LOAD_LIBRARY_SAFE(lib)                 \
    if (!delayload_##lib()) { exit (0); }      \
    void* lib = dlopen_ex (#lib".so");

#define LOAD_SYMBOL(sym, lib)                  \
    sym##_##t* sym = (sym##_##t*) dlsym (lib, #sym);

#define UNLOAD_LIBRARY(lib)                    \
    if (lib != NULL) {                         \
        dlclose (lib);                         \
    }

This is used as:

    plmcuda_EXPORT (
    void CUDA_selectgpu,
        int gpuid
    );
    ->
    typedef void CUDA_selectgpu_t (int gpuid);

    LOAD_LIBRARY_SAFE (libplmcuda);
    LOAD_SYMBOL (CUDA_selectgpu, libplmcuda);
    CUDA_selectgpu (parms->gpuid);
    UNLOAD_LIBRARY (libplmcuda);
    ->
    if (!delayload_libplmcuda()) { exit (0); }
    void* lib = dlopen_ex ("libplmcuda.so");
    CUDA_selectgpu_t* sym = (CUDA_selectgpu_t*) dlsym (lib, "CUDA_selectgpu");
    CUDA_selectgpu (parms->gpuid);
    if (lib != NULL) {
        dlclose (lib);
    }

******************************************************************************
Thoughts on operations of two images

Traditionally, plastimatch has resampled the non-reference image to match
the reference image when images of differing sizes are being operated on.

The traditional ITK method is to iterate the reference, and on each
pixel operation to test if the pixel location lies within the second image.

A third possible method would be to clip the second to the reference,
and then do an ITK-style test within the clipped region.  The Dice
code does something like this, with the caveat that no output is
produced, so both images are resampled down to the overlapping size.

******************************************************************************
Superbuild test configurations

Standard build: local ITK, local DCMTK
Standard build: system ITK, system DCMTK
Superbuild: system ITK, system DCMTK
Superbuild: download ITK, download DCMTK

******************************************************************************
Good ideas from 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

A) Multiple jobs, each with one fixed and one moving

   job1/fix.mha
   job1/mov.mha
   job2/fix.mha
   job2/mov.mha

*) Choose job1/fix.mha as fixed
*) Choose job1/mov.mha as moving
*) Click on "repeat for peer directories"

B) Multiple jobs, each with one fixed and many moving

   job1/fix.mha
   job1/mov1.mha
   job1/mov2.mha
   job2/fix.mha
   job2/mov1.mha
   job2/mov2.mha

*) Choose job1/fix.mha as fixed
*) Choose job1 as moving
*) Click on "repeat for peer directories"

C) Multiple jobs, all-to-all

   job1/img1.mha
   job1/img2.mha
   job1/img3.mha
   job2/img1.mha
   job2/img2.mha
   job2/img3.mha

*) Choose job1 as fixed
*) Click on "repeat for peer directories"

D) All-to-all with different directories

   dir/p1/img.mha
   dir/p2/img.mha
   dir/p3/img.mha

*) Choose dir as fixed
*) Click "recurse"
*) Unclick "repeat for peer directories"

******************************************************************************
DICOM export entry points
2016-10-19

Rt_study::save_dcmtk
Dcmtk_rt_study::save

Rt_study::save_gdcm
Segmentation::save_gdcm_rtss

******************************************************************************
Slice_list
2016-10-05

Used in:

base/dcmtk_rtss.cxx
base/rtss.cxx
base/rtss.h
base/rt_study_metadata.cxx

Slice_list is encapsulated inside rt_study_metadata.cxx.
- The get/set image_header function is based on Slice_list
- slice_list_apply
-- What does it mean?
--- called on rtss 
-- When is it called
- slice_list_complete
-- What does it mean?
--- set_image_header() and set_slice_list_complete() both were called
-- When is it called

******************************************************************************
register_gui
2016-09-01

Use cases for register_gui

A) Multiple jobs, each with one fixed and one moving

   job1/fix.mha
   job1/mov.mha
   job2/fix.mha
   job2/mov.mha

B) Multiple jobs, each with one fixed and many moving

   job1/fix.mha
   job1/mov1.mha
   job1/mov2.mha
   job2/fix.mha
   job2/mov1.mha
   job2/mov2.mha

C) Multiple jobs, all-to-all

   job1/img1.mha
   job1/img2.mha
   job1/img3.mha
   job2/img1.mha
   job2/img2.mha
   job2/img3.mha

******************************************************************************
cmake upgrade
2016-05-16

The cmake infrastructure will benefit from using the new tools for
creating packages.  New tools are available with CMake 2.8.11,
available since May 2013.  Here is my understanding of how this stuff
is supposed to work.

1) Create target 

add_library (libr src.cxx)

2) Assign property to library target

target_include_directories (libr INTERFACE
    $<INSTALL_INTERFACE:include/libr>)

I think you can also set target_link_libraries, which
would track library dependencies.

3) Install target with EXPORT option

install (TARGETS libr
    EXPORT LibrTargets
    )

It seems step 2 can be omitted by using the INCLUDES DESTINATION
option in install(TARGETS).  

4) Install export set

install (EXPORT LibrTargets
  DESTINATION "${PLM_INSTALL_CMAKE_DIR}"
  )

Do I need to specify the DESTINATION?  Will it do the right thing regardless?

5) Using the library

No need to do anything.  By creating an executable which depends on a
library target, the include directories are set appropriately.


******************************************************************************
xvi archive
2016-04-13

1) Handle multiple Rx (done)
2) Handle HFP/FFS/FFP (done)
3) Handle rotations (done)
4) Some form of series description and study description (done)
5) Correct dates (done)
6) Mark as CBCT (done)
7) Some form of window/level (done, supported by MIM 6.6)


******************************************************************************
WED
2016-03-09

Temporarily (?) removed functionality
- Computing aperture and range compensator (mode 2)
- Looping through angles (mode 3)


******************************************************************************
Proj_volume coordinates
2016-02-08

The main issue with the proj volume is that its coordinates are 
both difficult to understand and poorly documented.

What makes it difficult?
- ires vs image_dim vs dim
-- use image_dim
- is first index row or column?
-- dim[0] = cols, dim[1] = rows
-- loop (j=0;j<dim[1]-1;j++) {
--   loop (i=0;i<dim[0]-1;i++) { } }
- image_center vs image_origin
-- both are potentially useful
-- either should be specified, but internal storage as image origin
- location of first data point (at clipping plane or inside volume?)
-- ?
- different code for drr and wed
-- need to unify

What does ray_data contain?
- ray_data is computed from reference volume
- Includes test if ray intersects volume, front and back intersection 
  points, aperture intersection point, and ray norm
- compute_ray_data also sets the clipping planes

What files might the wed program create?
- proj_ct = HU in proj coordinates
- proj_wed = WED in proj coordinates
- proj_dose = dose in proj coordinates
- wed_ct = HU in WED coordinates
- wed_dose = dose in WED coordinates
- dew_ct = HU in proj coordinates
- dew_dose = dose in proj coordinates

What conversions are important?
- Convert ct to proj_wed
-- rpl.compute_rpl_PrSTRP_no_rgc
- Convert ct to proj_ct
- Convert proj_wed to ct

This thing needs removal
- compute_target_distance_limits_slicerRt

******************************************************************************
Rpl_volume
2015-12-21

An rpl_volume is a proj_volume.  The x,y dimensions are defined by 
the aperture, and the z dimension is along rays through the aperture.

The contents of the rpl_volume may be intensity (e.g. ct or dose) or 
depth (wepl).  

The units of the steps are either geometric or wepl.

Main functions:
  get_rgdepth - lookup values in volume
  compute_ray_data - this is called internally, but also by dose code;
       

  compute_farthest_penetrating_ray_on_nrm

  compute_proj_wed_volume - this seems to compute a 2D image
  compute_wed_volume - resample a Proj_vol into a Wed_vol
  compute_dew_volume - 

  apply_smearing_to_target
  compute_volume_aperture
  apply_beam_modifiers

  compute_beam_modifiers_passive_scattering
  compute_beam_modifiers_active_scanning

  rpl_ray_trace - call ray_trace_uniform on a single ray

  Why are there so many of these
  ------------------------------
  compute_rpl_void 
    -> No ray tracing performed
    -> WTF ?
  compute_rpl_ct_density
    -> rpl_ray_trace_callback_ct_density
    -> Schneider density, not accumulated
  compute_rpl_HU 
    -> rpl_ray_trace_callback_ct_HU
    -> HU, not accumulated
  compute_rpl_PrSTRP_no_rgc
    -> rpl_ray_trace_callback_PrSTPR
    -> Schneider stopping power, not accumulated
  compute_rpl_range_length_rgc
    -> rpl_ray_trace_callback_range_length
    -> Schneider stopping power, accumulated
  rpl_ray_trace_callback_PrSTPR_XiO_MGH (not called)

  Answer.  There are limitations in the ray tracing design which limit 
  reusability.
    -> May accumulate or not
    -> No real world coordinates / li_values

******************************************************************************
ITK Origin and Index
2015-08-18

It seems that ITK allows images for which the first pixel is a 
non-zero (but non-negative) index.  When using such images, care 
must be used.

Either, use the region and the (ITK) origin:

    const typename ImageType::PointType& og = input->GetOrigin();
    const typename ImageType::SpacingType& sp = input->GetSpacing();

Or, use the dimension and the (plastimatch) origin:


******************************************************************************
Image orientation
2015-08-13

DICOM is simple.  Coordinate system is always LPS.

a) (0020,0032) Image Position Patient: the world coordinate location of 
the center of the first voxel in the file.
b) (0020,0037) Image Orientation Patient: the real world direction cosines,
mapping an increment in voxel index to an increment in real-world location.
c) (0018,5100) Patient Position: does not affect mapping from voxel 
index to world coordinate.  But it can be used to display correct 
orientation on the screen (e.g. putting patient left on screen right 
for HFS).

ITK is simple.  However, not yet clear to me if coordinate system 
is always LPS.

a) Offset: the world coordinate location of the center of the first 
voxel in the file.
b) TransformMatrix: the real world direction cosines,
mapping an increment in voxel index to an increment in real-world location.
c) AnatomicOrientation: does not affect mapping from voxel index 
to world coordinate.

******************************************************************************
Bspline_parms
2015-06-10

1. Historically, it is not possible to include ITK include files 
   by the nvcc compiler.
2. Also historically, the itk include file is in plm_config.h
3. As a result, bspline_parms is needed, instead of accessing 
   stage_parms.

******************************************************************************
Proj_volume, Proj_image, Rpl_volume, and dose calculation
2015-05-06, 2016-03-16

:: Proj_volume

    Volume *vol;
    Proj_matrix *pmat;
      double ic[2];
      double matrix[12];
      double sad;
      double sid;
      double cam[3];
      double nrm[3];
      double extrinsic[16];
      double intrinsic[12];
    int num_steps;
    double step_length;
    int image_dim[2];
    double image_spacing[2];
    double clipping_dist[2];
    double nrm[3];
    double src[3];
    double iso[3];
    double ul_room[3];
    double incr_r[3];
    double incr_c[3];

* Proj_volume is defined in documentation with a projective geometry.
  But it seems to be implemented as a spherical geometry.
* It is used by rpl_volume, dose
* It is not used by drr, fdk
* Regarding Proj_matrix:
   - Can be used by Siddon approach, does not depend on uniform steps
   - Has no knowledge of projection plane dimension, spacing

:: Proj_image
    int dim[2];              /* dim[0] = cols, dim[1] = rows */
    double xy_offset[2];     /* Offset of center pixel */
    Proj_matrix *pmat;
      double ic[2];
      double matrix[12];
      double sad;
      double sid;
      double cam[3];
      double nrm[3];
      double extrinsic[16];
      double intrinsic[12];
    float* img;		     /* Pixel data */

* Note use of raw pixel data
* Spacing gets encoded in pmat
* Proj_image could be a 1D Proj_vol

:: Aperture
   Private:
    Plm_image::Pointer aperture_image;
    Plm_image::Pointer range_compensator_image;
    double distance;
    int dim[2];
    double center[2];
    double spacing[2];
   Public:
    double vup[3];        /* orientation */
    double ic_room[3];    /* loc of center (room coords) */
    double ul_room[3];    /* loc of upper left corder (room coords) */
    double incr_r[3];     /* row increment vector */
    double incr_c[3];     /* col increment vector */
    double nrm[3];        /* unit vec: normal */
    double pdn[3];        /* unit vec: down */
    double prt[3];        /* unit vec: right */
    double tmp[3];

* Projection plane geometry and proton hardware
* Maybe two separate distances would be helpful
* Reimplements concepts of Proj_matrix
* Why not two separate Proj_image with same Proj_matrix?
* Why pdn instead of pup?

:: Projection
    Canonical
      double src[3];
      double iso[3];
      double sid;
      int image_dim[2];            // [0] = columns, [1] = rows
      double image_center[2];      // in pixels
      double image_spacing[2];     // spacing on detector
      double vup[3];
    Optional
      double clipping_dist[2];
    Derivative
      double matrix[12];
      double extrinsic[16];
      double intrinsic[12];
      double sad;            // || src - iso ||
      double nrm[3];         // src - iso / || src - iso ||
      double plt[3];         // nrm x vup / || nrm x vup ||
      double pup[3];         // plt x nrm
      double ic_room[3];     // src - sad * nrm
      double incr_c[3];      // ic_room - image_center[0] * isp[0] * pup
      double incr_r[3];      // ic_room + image_center[1] * isp[1] * plt
      double ul_room[3];     // ic_room - ic[0] * incr_c - ic[1] * incr_r

* Replaces Proj_matrix and Aperture

:: IEC
      double gantry_angle;
      double couch_angle;
      double detector_angle;
      double I_f;       // SAD (?)
      double I_r;       // detector distance
      double I_p[3];    // patient offset
      double Rx, Ry;    // image center
      N.b. IEC does not describe image resolution or spacing

:: DICOM RT Image
      General Image (C.7.6.1)
      Image Pixel (C.7.6.3)
        Rows
	Columns
      RT Image (C.8.8.2)
	X-Ray Image Receptor Translation       // IEC
	X-Ray Image Receptor Angle             // IEC
        RT Image Plane, RT Image Orientation   // out-of-plane rotations
	Image Plane Pixel Spacing
	RT Image Position                      // 2D coords of first pixel
	Radiation Machine SAD
	RT Image SID
	Source to Reference ObjectDistance
	Gantry Angle
	Gantry Pitch Angle
	Patient Support Angle
	Table Top Eccentric AxisDistance
	Table Top Eccentric Angle
	Table Top Pitch Angle
	Table Top Roll Angle
	Table Top Vertical Position
	Table Top LongitudinalPosition
	Table Top Lateral Position
	Isocenter Position
	Patient Position

* Strangely, no Image Plane module seems required (or even allowed?), 
  which would define Image Position Patient, Image Orientation Patient

:: Other thoughts

* The Aperture class demonstrates that you may have multiple 
proj_image with same proj_matrix.  A few mild assumptions are used:
image pixels are matched and clipping plane is same.
Backprojection will map voxels correctly in both proj_image.

Alternative implementation as master-slave, using Proj_image 
for aperture_image and Volume for range_compensator_image could also 
be considered.

******************************************************************************
Older stuff

***** Metadata hookup *****

Current status:
Rt_study_metadata constructor hooks up internally created metadata
Segmentation allows external hookup of parent in constructor.  

DCMTK loading puts items into Rt_study_metadata.  It puts the info 
directly into the right section.  Ditto for GDCM1.

Synthetic_mha creates images and inserts images into an Rt_study.

XiO loader (Rt_study::load_xio) inserts items directly into Rt_study_metadata.

Metadata within Plm_image is never actually used.
You must have an Rt_study to have metadata.
The Rt_study_metadata is passed into Plm_image::save()


***** Metadata ownership *****

Current ownership organization

Rt_study -> Rt_study_metadata
Rt_study_metadata -> shared metadata
Rt_study_metadata -> image metadata
Rt_study_metadata -> dose metadata
Rt_study_metadata -> rtss metadata

Plm_image -> image metadata
Plm_image -> dose metadata
Segmentation -> rtss metadata

image metadata -> shared metadata
rtss metadata -> shared metadata
dose metadata -> shared metadata

***** Bspline methods *****

Method mi-i
Tile loop to create histogram (hist_add omp_v2)
Condense loop to create gradient

Method mi-h 
Serial loop to create histogram
Condense loop to create gradient

Method mi-g == method mi-h

Method mi-f
Tile loop to create histogram (hist_add omp_crit)
Condense loop to create gradient

Method mi-e
Tile loop to create histogram (hist_add omp_v1)
Condense loop to create gradient

Method d == method h

Method mi-c
Serial loop to create histogram
Serial loop to create gradient

Method mse-i
Parallel tile

Method mse-h
Serial tile

Method mse-g == mse-i

Method mse-c
Serial voxel

Method k
Serial loop

Method l
Serial tile loop, condense with sets


***** Overlap fraction *****

The overlap fraction should (?) be tied to score at initial iteration.
This requires stashing the initial score somewhere.  But this needs to 
be done in a general way for various optimizers.

Furthermore, the "best score" concept is probably not implemented for 
the non-Nocedal optimizers.

This is a TODO.

***** Programmability redux *****

Option 1) Internal programmability, with lua
Effort: medium
Pro: Convenient
Con: Lua not popular

Option 2) Internal programmability, with internal language
Effort: medium-high
Pro: Convenient for existing users, not so difficult to implement
Con: Custom languages are lame

Option 3) External wrapping, a la VTK
Effort: medium
Pro: Python popular
Con: 

Option 4) External wrapping with Swig
Effort: medium
Pro: Python popular, other languages supported
Con: 

***** Restartable registration (second try) *****

After a lot of effort, I learned that you can't simply code up 
something like suggested on the ITK web site to create a semaphore
from a condition variable [1].  Doing so does not work, because the 
condition variable does not guarantee that the signalee gets the 
resource before the signaller can re-grab.  N.b. that the DLIB 
implementation has the same problem.

Therefore instead, let's try a producer-consumer style solution, 
with two locks.

master_grab:
  mutex.lock
    slave_waits = true
    master_waits = true
    while master_waits == true
      master_sema.wait       // wait for slave to finish
  mutex.unlock

master_release:
  mutex.lock
    slave_waits = false
    slave_sema.signal      // wake up slave
  mutex.unlock

slave_grab:
  mutex.lock
    while slave_waits == true
      slave_sema.wait      // slave waits to get woken up
  mutex.unlock

slave_release:
  mutex.lock
    master_waits = false;
    master_sema.wait      // slave waits to get woken up
  mutex.unlock

http://itk.org/migrationv4/index.php?action=artikel&cat=3&id=108&artlang=en

***** Restartable registration *****

Here is how it looks using ITK methodology

reg_func:
  halt_sem.Down();
  // do registration
  halt_sem.Up ();

start_registration:
  halt_sem.Initialize (1);
  id = spawn thread(reg_func);
  return;

halt_registration:
  halt_sem.Down();
  return;

wait_for_complete:
  threader.TerminateThread (id)


***** ITK and plastimatch direction cosines *****

There are two ways to have a rotated volume.  The direction cosines 
of the volume might be inherently rotated, or there might be a rigid 
transform associated with it.

ITK direction cosines are stored in the columns of the array.
In other words, if the (DICOM) orientations are A, B, and C 
for the i (fastest), j, and k (slowest) indices, then ITK stores 
them like this:

  itk_dc[0][0] = A[0];
  itk_dc[0][1] = B[0];
  itk_dc[0][2] = C[0];
  itk_dc[1][0] = A[1];
  itk_dc[1][1] = B[1];
  itk_dc[1][2] = C[1];
  itk_dc[2][0] = A[2];
  itk_dc[2][1] = B[2];
  itk_dc[2][2] = C[2];

The plastimatch direction cosines are stored in a one-dimensional
array, also by columns.  

  dc[0] = A[0];
  dc[1] = B[0];
  dc[2] = C[0];
  dc[3] = A[1];
  dc[4] = B[1];
  dc[5] = C[1];
  dc[6] = A[2];
  dc[7] = B[2];
  dc[8] = C[2];

These are then converted into the "step" and "proj" matrices.

  step[0] <- spacing[0] * dc[0] == spacing[0] * itk_dc[0][0]
  step[1] <- spacing[1] * dc[1] == spacing[1] * itk_dc[0][1]
  step[2] <- spacing[2] * dc[2] == spacing[2] * itk_dc[0][2]
  step[3] <- spacing[0] * dc[3] == spacing[0] * itk_dc[1][0]
  ...
  step[8] <- spacing[2] * dc[8] == spacing[0] * itk_dc[2][2]

To convert an index into a position, you do this:

  pos[0] = origin[0] + idx[0]*step[0] + idx[1]*step[1] + idx[2]*step[2]
  pos[1] = origin[1] + idx[0]*step[3] + idx[1]*step[4] + idx[2]*step[5]
  pos[2] = origin[2] + idx[0]*step[6] + idx[1]*step[7] + idx[2]*step[8]

***** How to delete items from conquest *****

./dgate --deletepatient:patid

Note: supports wildcards, such as:

./dgate --deletepatient:0522*

***** Subsampling framework *****

legacy vox subsampling      Voxel binning, new voxel center at bin center
new vox subsampling         Convert into standard resampling, allow fraction
mm resampling               Choose by mm
pct resample                Choose by pct of original voxels
dim resample                Choose by number of voxels

res,res_vox,ss
res_mm
res_pct
res_dim

***** When is itk vs native resample used? *****

native:
xform.cxx                       resample gpuit vfs
demons,bspline,transl           registration subsampling

itk:
everywhere else


***** How to detect a "Null" smart pointer *****

Just like a regular pointer.

Plm_image::Pointer p;
if (p) {
   /* Will not be executed because p is null */
}

You can return a null pointer like this:

if (error) {
  return Plm_image::Pointer();
}

***** Plastimatch 2.0 *****

Proposal #1, extend existing language.  The below is an example,
but many improvements could be made.

[GLOBAL]
fixed[0]=image_1a.mha           // support for multi-planar registration
fixed[1]=image_1b.mha
moving[0]=image_2a.mha
moving[1]=image_2b.mha
$aux=image_1a_mask.mha          // load image into a variable
img_out[0]=warped_1a.mha

[FILTER]
action=dmap                     // could be lua script here...
input_1=$fixed[0]               // set input from variable
input_2=$aux                    // set input from variable
input_3=image_1c.mha            // load image into a variable
$f1=$fixed[0]                   // save a copy of the old fixed[0]
fixed[0]=$output                // overwrite fixed[0] with filter output

[STAGE]
xform=translation
optim=rsg
max_its=30
res=4 4 2

[RESUME_STAGE]                  // continue existing stage (yuck)
max_its=50

[STAGE]
fixed[0]=$f1                    // replace fixed image for this stage
xform=bspline

Proposal #2, extend lua scripting.  Something like this:

-- Global (inputs)
r = Registration()
r:fixed[0] = Image.load("image_1a.mha")
r:fixed[1] = Image.load("image_1b.mha")
r:moving[0] = Image.load("image_2a.mha")
r:moving[1] = Image.load("image_2b.mha")
aux = Image.load("image_1a_mask.mha")

-- Filter
f1 = fixed[0]
r:fixed[0] = Dmap:get_output (r:fixed[0], aux, Image.load("Image_1c.mha"))

-- Stage
s = r:Stage ()
s:xform = 'translation'
s:optim = 'rsg'
s:max_its = 30
s:res = '4 4 2'
s:run()

-- Stage (continuation)
s:max_its = 30
s:run()

-- Stage
s = r:Stage(s)
s:fixed[0] = f1
s:xform = 'bspline'
s:run()

-- Global (outputs)
r:get_output():save("warped_1a.mha")


***** What to do about const smart pointers *****

(Your answer here)


***** A trick for forward declaration of nested classes *****

http://stackoverflow.com/questions/2600385/c-nested-class-forward-declaration-issue

(Not the first answer that was accepted though.  The second one 
is the one you want.)


***** Rt_study API example *****

/* Example #1, simple save using images */
itk::Image<short,3>::Pointer itk_image;
itk::Image<float,3>::Pointer itk_dose;
itk::Image<unsigned char,3>::Pointer itk_structure_1;
itk::Image<unsigned char,3>::Pointer itk_structure_2;

Rt_study rt_study;
rt_study.set_image (itk_image);
rt_study.set_dose (itk_dose);
rt_study.add_structure (itk_structure_1, "Body", "255\\0\\0");
rt_study.add_structure (itk_structure_2, "Tumor", "0\\255\\0");
rt_study.save ("output_directory");


/* Example #2, save structure set that references existing CT image */
Rt_study rt_study;
rt_study.add_structure (itk_structure_1, "Body", "255\\0\\0");
rt_study.add_structure (itk_structure_2, "Tumor", "0\\255\\0");

const char *study_uid, *ct_series_uid, *for_uid;
Rt_study_metadata::Pointer = rt_study.get_study_metadata();
rt_study_metadata.set_study_uid (study_uid);
rt_study_metadata.set_ct_series_uid (ct_series_uid);
rt_study_metadata.set_frame_of_reference_uid (for_uid);
rt_study_metadata.set_study_metadata (0x0010, 0x0010, "PATIENT^NAME");
rt_study_metadata.set_study_metadata (0x0010, 0x0020, "PATIENT^ID");

itk::Image<short,3>::Pointer itk_image;
rt_study_metadata.set_image_header (itk_reference_image);
for (int slice = 0; slice < num_slices; slice++) {
    rt_study_metadata.set_slice_uid (slice, uid_string[slice]);
}

rt_study.save ("output_directory");


***** Which metadata goes where? *****

PatientPosition ?
StudyID ?

***** Rtss, rtss_structure_set, ... *****

These names are lousy.  Let's get some new names.

DICOM officially refers to the set of all structures 
as a "RT Structure Set".  The image associated with the structures 
is called a "Contour Image Sequence".  A single structure is 
called an "ROI".  A single polyline is called an "ROI Contour".

Proposed names (polyline types)

  - Rtss_contour          replaces Rtss_polyline
  - Rtss_roi              replaces Rtss_structure
  - Rtss                  replaces Rtss_structure_set

Proposed names (image & polymorphic types)

  - Segmentation          replaces Rtss
  - Segmentation_image    replaces Ss_img


***** Smart pointers part 3 *****

Things to fix

- Plm_image::steal_volume () should be removed
- Rtds::load_dcmtk (const char *dicom_path) - need to be fixed


***** Smart pointers redux *****

Prefer to have "internal" smart pointers

Dlib has 3 kinds

#include "smart_pointers/scoped_ptr.h"
#include "smart_pointers/shared_ptr.h"
#include "smart_pointers/weak_ptr.h"

- shared_ptr is a standard smart pointer
- weak_ptr is a shared_ptr that can go away; you make a special call to 
  see if it's still there
- scoped_ptr doesn't have reference counting

***** DICOM re-org 2013-03-24 *****

Future plan:

Dicom_rt_study
  -> Various metadata
  -> Dcmtk_rt_study
    -> Backpointer to Dicom_rt_study
    -> More metadata
    -> Dcmtk_series (dose) // currently in dcmtk_loader
    -> Dcmtk_series (rtss) // currently in dcmtk_loader
    -> Dcmtk_series (img)  //??
  -> cxt    // currently in dcmtk_loader
  -> dose   // currently in dcmtk_loader
  -> img    // currently in dcmtk_loader

***** MABS re-org *****

Prep/training steps:
(1) convert file format
(2) do registrations, compute dice, possibly optimize registration
(3) warp structures and get distance maps
(4) optimize voting parameters (rho, sigma, thresh)

Workflow -- optimizing registrations
------------------------------------
convert file format
for each image pair
  for each registration parameter
    register
    warp structures
    compute distance maps
    compute dice
    tabulate results
  choose best registration parameter

Workflow -- optimizing voting parameters
----------------------------------------
convert file format
for each image pair
  register
  warp structures
  compute distance maps
for each structure
  for each voting parameter
    for each image pair
      load dmap
      vote
    save weights
    for each thresh
      threshold image
      compute dice
      save results

Workflow -- standard usage
--------------------------
for each image pair
  register
  warp structures
  for each structure
    compute distance maps
    vote
    threshold image
  

Other thoughts:
(1) Make dmap, dice faster

***** Geometry chooser *****

Two use cases.

Use case one:
- Manual overrides
- Fixed image
- Input image

Use case two:
- Manual overrides
- Fixed image
- Reference image
- Compare image

***** DICOM re-org *****

Need patient, study, series hierarchy.

------ Plm_patient
  ---- Plm_study
    -- Plm_series

This should be allowed to be created via dicom.  It might therefore 
be required to move rtss/rtds code into base.  These files would move:

Idea (1).  Plm_series has a "type" field, which tells us if the 
item is an image, rtss, etc.

Idea (2).  Plm_series is a base type, subclassed by image, rtss, etc.

***** Viscous *****

It seems that only certain versions of thrust work with certain versions 
of cuda.

Thrust 1.6.0 does not work with CUDA 3.0
Thrust 1.4.0 does work with CUDA 3.0

***** Metadata Mark II *****

Do we need separate metadata items for image, dose, and rtstruct?
Not sure.  Here are the considerations:

- ITK dicom write (image) requires setting metadata into itk image
- CXT, xio formats need somewhere to store the metadata
- RDD has its own metadata

Where does RTSS metadata get used (version 1.5.9)

- cxt_io.cxx
  - name, id, sex (rtss meta)
  - study id, ct study id, ct series id, ct for id (rdd)
- gdcm1_rtss.cxx
  - name, id, sex, series description
  - study id, ct study id, ct series id, ct for, ct slice ids (rdd)

Where RDD metadata get used (version 1.5.9)

- rtds.cxx
  - name, id, sex, patient position
  - (xio ct transform -- this should be part of metadata??)
- gdcm1_rdd.cxx
  - name, id, sex, patient position

Options: 

(a) All in rtds.
    PRO: simple, heterogenous data structure makes sense
    CON: registration code (and other code which doesn't use rtds) 
    	 still needs somewhere to store metadata
(b) Separate metadata for each item
    PRO: more similar to dicom, works well with registration code
    CON: difficult to synchronize

Final choice:

- Separate metadata for image, struct, dose
- Special structure for ct uids, etc.  These go in rtds instead of image
  (as they are now), because we might have a referenced dicom dir, without 
  an actual image.

***** Debian notes *****

In order to install ITK 3.20, you need to use unstable repository.
Here is what you need:

  sudo apt-get -V install -t unstable \
    libgdcm2-dev libinsighttoolkit3-dev libvtk5-dev

It seems that Debian ITK was built with GDCM 2.X instead of GDCM 1.X.
Too bad.

***** Organization of learning code *****

Use cases:

image: can be 2d (slice) or 3d (vol)
pos: can be 1d (slice loc), 2d (in-plane), or 3d (position)
binary (in/out, male/female)
tri-state (above, near, below)
continuous tri-state (above (+1), near (-1 to +1), below (-1))
conditional position (inside (with position), outside (without position))

- T-spine

slice -> slice loc
slice -> in-plane

- Lung apex

slice -> continuous tri-state

- T-spine

slice + continuous tri-state -> slice loc

Finding training data:

T-spine: Choose only slice or vol centered at fiducial
T-spine: Interpolate fiducials, use all slices
Lung apex: Choose only slice at apex
Lung apex: Choose all slices, compute distance to apex
Lung volume: Choose all slices intersecting mask

Transition plan:

Use hard-coded training routines for different use cases

plastimatch autolabel-train \
    --task t-spine-v1 \
    --input dir \
    --output net

The data needs a hierarchy, to allow for cross-validation on a 
patient-by-patient basis.  Call the data for a single patient 
an Autolabel_data_item

Autolabel_data_item {
  dlib::matrix inputs;
  dlib::matrix outputs;
}

Autolabel_data {
  std::list<Autolabel_data_item>
  choose_subset ()
}

Autolabel_trainer {
  Autolabel_data ad;
  train (parameter_range) {
    for (num_trials) {
      dlib::matrix training_data = ad.choose_subset();
    }
  }
}


***** Organization for irregular volume (transition plan) *****

(1) Use native, not ITK

(2) Only support volumes with irregular slice spacing.  No support 
for things like changing pixel size or direction cosines

(3) Add irregular volume as a member of Volume

class Volume {
      /* Regular volume stuff */
      int npix;
      void *data;

      /* Irregular volume stuff */
      float *irr_spacing;
      void **irr_data;
};

***** Writing a Slicer4 loadable module *****

(1) Use the wizard to make a template

export SD=$HOME/build/slicer-4/Slicer4
python ${SD}/Scripts/ModuleWizard.py \
       --template ${SD}/QTModules/ModuleTemplate \
       --target MY_MODULE_NAME \
       MY_MODULE_NAME

(2) Modify CMakeLists.txt

find_package (Slicer QUIET)
if (SLICER_FOUND)
  include ("${Slicer_USE_FILE}")
  if (SLICER_IS_SLICER4)
    add_subdirectory (QTModules/MY_MODULE_NAME)
  endif ()
endif ()

(3) Copy over TestingMacros.h

cp ${SD}/TestingMacros.h MY_MODULE_NAME

At this point you can compile, and it runs.  But it builds directly 
into the slicer directory.  This can be (partly) defeated using 
the following strategy, but it is a moot point because you can't yet 
set the module search path.  Here is the strategy:

(4) Defeat Slicer overwriting CMAKE_* variables

  if (Slicer_USE_FILE)
    set (OLD_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
    set (OLD_CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
    set (OLD_CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY})

    include ("${Slicer_USE_FILE}")

    set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OLD_CMAKE_RUNTIME_OUTPUT_DIRECTORY})
    set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OLD_CMAKE_LIBRARY_OUTPUT_DIRECTORY})
    set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OLD_CMAKE_ARCHIVE_OUTPUT_DIRECTORY})
  endif ()

(5) Edit CMakeLists.txt files generated by the python script.  
There are two files to edit: MY_MODULE_NAME/CMakeLists.txt, 
and MY_MODULE_NAME/Logic/CMakeLists.txt.

(5a) For MY_MODULE_NAME/CMakeLists.txt, do the following:

set (lib_name qSlicer${qt_module_name}Module)
set_target_properties (${lib_name} PROPERTIES
  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_BIN_DIR}"
  LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}"
  ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}"
  )

(5b) For MY_MODULE_NAME/Logic/CMakeLists.txt, do the following:

SlicerMacroBuildModuleLogic(
  NAME ${module_logic_name}
  DISABLE_WRAP_PYTHON
  EXPORT_DIRECTIVE ${module_logic_export_directive}
  INCLUDE_DIRECTORIES ${module_logic_include_directories}
  SRCS ${module_logic_SRCS}
  TARGET_LIBRARIES ${module_logic_target_libraries}
  )

set_target_properties (${module_logic_name} PROPERTIES
  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_BIN_DIR}"
  LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}"
  ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}"
  )

***** Proton dose ideas *****

Stage 1(a): Compute pencil beam in standard grid
(z direction is pdd in water)
(x-y direction is scatter in water, or just 1-d with distance)

Stage 1(b): Compute RPL in interpolated coordinate system
(z axis is beam axis)
(x-y perpendicular to beam, arbitrary v-up vector)

Stage 2: For each voxel
  a) Look up primary in RPL grid
  b) Convolve to find scatter within x-y axis of primary grid (ignoring tilt)

***** File browser design *****

http://www.xvsxp.com/files/file_browsing.php
http://rixstep.com/4/0/xfile/ss.shtml
http://www.ragesw.com/products/explorer/screenshots/1/

***** Writing to stdout in Qt *****

    QTextStream(stdout) << QString("foo") << "\n";

***** dgate quite ref (for wormwood) *****

cd ~/build/conquest-1.4.15
./dgate &

***** dcmtk quick ref *****

Run the dicom server like this:

  $ dcmqrscp

It will read a file "dcmqrscp.cfg" in the current directory, which is used 
to set user/group, port, AET, storage directory.  NOTE: Be very careful 
about extra spaces in the list of remote AETs.  Here the file I used 
for these tests:

--- begin here ---
NetworkType     = "tcp"
NetworkTCPPort  = 9885
MaxPDUSize      = 16384
MaxAssociations = 16
Display         = "no"
UserName        = "gsharp"
GroupName       = "gsharp"
HostTable BEGIN
entry1           = (MOVESCU, localhost, 19530)
entry2           = (STORESCP, localhost, 19335)
HostTable END
VendorTable BEGIN
VendorTable END
AETable BEGIN
READWRITE     /home/gsharp/projects/dicom-test/junk RW (10, 1024mb)  ANY
AETable END
--- end here ---

Send files to database like this:

  $ storescu -aec READWRITE localhost 9885 *.dcm

Query the database like this:

  $ findscu -P -k 0010,0010 -k 0008,0052=PATIENT -aec READWRITE localhost 9885

Retrieve from the database like this:

  $ movescu -v --patient -aet MOVESCU -aem MOVESCU -aec READWRITE --port 19530 -k 0008,0052=PATIENT -k 0010,0020=PL811332912032439 localhost 9885

Or like this:

  $ storescp 19335 &
  $ movescu -v --patient -aet MOVESCU -aem STORESCP -aec READWRITE -k 0008,0052=PATIENT -k 0010,0020=PL811332912032439 localhost 9885


***** Proposed engineering changes: Aug 1, 2009 *****

1) Reduce number of executables

   Old:
     plastimatch [options]
     dicom_to_mha [options]
     warp_mha [options]
   New:
     plastimatch register [options]
     plastimatch convert [options]
     plastimatch warp [options]

   "Simple" executables such as bspline.exe, drr_c.exe etc. will not 
   be merged.

2) Add threading options to plastimatch

   Old:
     implementation=gpuit_cpu
   New:
     implementation=plastimatch
     threading=openmp
     max_threads=2

3) Remove gpuit sub-library, merge into plastimatch1.lib

4) Move source code to src/ subdirectory

***** How to compile libf2c *****

Edit libf2c/makefile.vc, and change:
  CFLAGS = -DUSE_CLOCK -DMSDOS -DNO_ONEXIT -Ot1

To:
  CFLAGS = -DUSE_CLOCK -DMSDOS -DNO_ONEXIT -Ot1 -MD

Edit libf2c/fio.h, and comment out:
  extern int isatty(int);

***** How to compile the .br into .cpp *****

The default compile is simply: 
   brcc -o outfile.cpp infile.br

The FDK code doesn't work for PS20 & ARB targets.

We can use -p flag to set the platform.
   brcc -o outfile.cpp

***** How to compile brook on cygwin/g++ *****

1) The config/DetectOS thing always gets Windows_NT because 
the $OS environment variable is standard in Windows.

2) Need to create a new *.mk file  (To be done)

3) It seems to build OK, but doesn't completely solve the 
problem.  fxc still requires windows style paths, maybe cgc does too.

***** Threads vs OpenMP *****

http://www.intel.com/cd/ids/developer/asmo-na/eng/technologies/threading/hyperthreading/53797.htm

https://computing.llnl.gov/tutorials/openMP/

On GCC:
  gcc -fopenmp openmp_test.c

Visual studio 2005 supports OpenMP 2.0
  cl /openmp

Express version does not support OpenMP (except as described below)
  http://blog.codekills.net/archives/25-OpenMP-and-Visual-C++-the-free-way-sorta.html
MinGW gcc OpenMP is still not fully supported
  http://www.nabble.com/OpenMP-and-shared-libgcc-td17516165.html

***** What is the deal with ITK's oriented images? *****

http://www.itk.org/pipermail/insight-users/2008-August/027102.html

Now, ITK 3.10.2 has two flags (earlier version are similar).
The use of these flags are not well described.

ITK_USE_ORIENTED_IMAGE_DIRECTION
ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE

***** Logging *****

For "C" logging, I found 2 projects:

- log4c (LGPL license)
- pantheios (BSD license)

***** Timing *****

Options:
1) clock()
2) time()
3) gettimeofday()
4) QueryPerformanceCounter  // windows only
5) OpenMP timer
6a) clock_gettime(CLOCK_MONOTONIC)
6b) clock_gettime(CLOCK_REALTIME)
6c) clock_gettime(CLOCK_HIGHRES) // solaris only?

http://en.wikipedia.org/wiki/Real-time_clock
http://en.wikipedia.org/wiki/High_Precision_Event_Timer

http://cboard.cprogramming.com/c-programming/106025-clock-vs-gettimeofday.html
http://fixunix.com/linux/6645-negative-response-time-gettimeofday.html
http://code.google.com/p/high-resolution-timer/source/browse/trunk/highrestimer/c%2B%2B_library/wraper_and_library/timer_library.c

***** SVN eol-goop *****

Put the following in your ~/.subversion/config

CMakeLists.txt = svn:eol-style=native;svn:mime-type=text/plain
Makefile = svn:eol-style=native;svn:mime-type=text/plain
README* = svn:mime-type=text/plain;svn:eol-style=native
readme* = svn:mime-type=text/plain;svn:eol-style=native

*.tga = svn:mime-type=image/tga
*.bat = svn:mime-type=text/plain;svn:eol-style=CRLF
*.br = svn:eol-style=native;svn:mime-type=text/plain
*.c = svn:eol-style=native;svn:mime-type=text/plain
*.cmake = svn:mime-type=text/plain;svn:eol-style=native
*.cmd = svn:mime-type=text/plain;svn:eol-style=CRLF
*.cpp = svn:eol-style=native;svn:mime-type=text/plain
*.cu = svn:eol-style=native;svn:mime-type=text/plain
*.cxx = svn:eol-style=native;svn:mime-type=text/plain
*.dsp = svn:eol-style=CRLF;svn:mime-type=text/plain
*.dsw = svn:eol-style=CRLF;svn:mime-type=text/plain
*.f = svn:eol-style=native;svn:mime-type=text/plain
*.h = svn:eol-style=native;svn:mime-type=text/plain
*.jpg = svn:mime-type=image/jpeg
*.m = svn:eol-style=native;svn:mime-type=text/plain
*.pl = svn:eol-style=native;svn:mime-type=text/plain;svn:executable
*.png = svn:mime-type=image/png
*.pm = svn:eol-style=native;svn:mime-type=text/plain
*.sh = svn:mime-type=text/plain;svn:eol-style=LF;svn:executable
*.txt = svn:mime-type=text/plain;svn:eol-style=native
*.xml = svn:mime-type=text/xml;svn:eol-style=native
