├── .gitignore ├── rti ├── topas │ ├── tutorial │ │ ├── .gitignore │ │ ├── Abdomen │ │ │ ├── 1.dcm │ │ │ ├── 2.dcm │ │ │ ├── 3.dcm │ │ │ ├── rtdose.dcm │ │ │ └── README.txt │ │ ├── inputs.txt │ │ ├── QA_view.txt │ │ ├── beam_view.txt │ │ ├── plan_hu_view.txt │ │ ├── view.txt │ │ ├── plan_tutorial.txt │ │ ├── QA_tutorial.txt │ │ ├── QA.txt │ │ ├── plan.txt │ │ └── beam.txt │ └── rtion │ │ ├── TsRTIonSourceGenerator.hh │ │ ├── TsRTIonSource.hh │ │ ├── TsRTIonSourceGenerator.cc │ │ ├── TsRTIonComponents.hh │ │ └── TsRTIonSource.cc ├── treatment_machines │ └── rbe │ │ ├── rtip_demo.dcm │ │ ├── rbe1p1.table │ │ ├── rbe_1p1.hpp │ │ └── rbe_1p1_complete.hpp ├── base │ ├── rti_distributions.hpp │ ├── rti_beam_module_rt.hpp │ ├── rti_common.hpp │ ├── rti_beam_module.hpp │ ├── rti_vertex.hpp │ ├── rti_stopping_power.hpp │ ├── rti_rangeshifter.hpp │ ├── distributions │ │ ├── rti_const_1d.hpp │ │ ├── rti_norm_1d.hpp │ │ ├── rti_uni_1d.hpp │ │ ├── rti_pdfMd.hpp │ │ ├── rti_phsp6d.hpp │ │ └── rti_phsp6d_fanbeam.hpp │ ├── rti_beamline.hpp │ ├── rti_aperture.hpp │ ├── rti_geometry.hpp │ ├── rti_beamlet.hpp │ ├── rti_treatment_machine.hpp │ ├── rti_rect2d.hpp │ ├── rti_coordinate_transform.hpp │ ├── rti_beam_module_ion.hpp │ ├── rti_beamsource.hpp │ ├── rti_utils.hpp │ ├── rti_track.hpp │ ├── rti_rtdose.hpp │ ├── rti_ct.hpp │ ├── rti_vec.hpp │ ├── rti_treatment_session.hpp │ ├── rti_treatment_machine_ion.hpp │ └── rti_matrix.hpp └── test │ └── session │ ├── pbs_generic.table │ ├── CMakeLists.txt │ ├── cli_rti.hpp │ ├── treatment_session.cpp │ └── hist.txt ├── gdcm-2.6.include.tar.gz ├── CMakeLists.txt ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /gdcm-2.6/ 2 | -------------------------------------------------------------------------------- /rti/topas/tutorial/.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.binheader 3 | -------------------------------------------------------------------------------- /gdcm-2.6.include.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topasmc/dicom-interface/HEAD/gdcm-2.6.include.tar.gz -------------------------------------------------------------------------------- /rti/topas/tutorial/Abdomen/1.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topasmc/dicom-interface/HEAD/rti/topas/tutorial/Abdomen/1.dcm -------------------------------------------------------------------------------- /rti/topas/tutorial/Abdomen/2.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topasmc/dicom-interface/HEAD/rti/topas/tutorial/Abdomen/2.dcm -------------------------------------------------------------------------------- /rti/topas/tutorial/Abdomen/3.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topasmc/dicom-interface/HEAD/rti/topas/tutorial/Abdomen/3.dcm -------------------------------------------------------------------------------- /rti/topas/tutorial/Abdomen/rtdose.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topasmc/dicom-interface/HEAD/rti/topas/tutorial/Abdomen/rtdose.dcm -------------------------------------------------------------------------------- /rti/treatment_machines/rbe/rtip_demo.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topasmc/dicom-interface/HEAD/rti/treatment_machines/rbe/rtip_demo.dcm -------------------------------------------------------------------------------- /rti/topas/tutorial/Abdomen/README.txt: -------------------------------------------------------------------------------- 1 | The DICOM example contained here is courtesy of the Geant4 Collaboration. 2 | The file was taken from Geant4's examples/extended/medical/DICOM 3 | 4 | rtdose.dcm was created by TOPAS team to demonstrate the creation of dosegrid from RTDOSE 5 | -------------------------------------------------------------------------------- /rti/topas/tutorial/inputs.txt: -------------------------------------------------------------------------------- 1 | # ===== # 2 | s:Rt/RTION/PlanFile = "../../treatment_machines/rbe/rtip_demo.dcm" 3 | s:Rt/RTION/DoseFile = "Abdomen/rtdose.dcm" 4 | s:Rt/RTION/CTDirectory = "Abdomen" 5 | u:Rt/RTION/ParticlesPerHistory = -1 6 | #s:Rt/RTION/BeamNameToBeSimulated = "270A1" 7 | i:Rt/RTION/BeamNumberToBeSimulated = 1 8 | -------------------------------------------------------------------------------- /rti/base/rti_distributions.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RTI_DISTRIBUTIONS_H 3 | #define RTI_DISTRIBUTIONS_H 4 | 5 | /// \file 6 | /// 7 | /// Distribution functions (meta-header file for all distributions) 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #endif 18 | 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | project (dicom-interface) 4 | 5 | add_library(dicom_interface INTERFACE) 6 | 7 | target_compile_features(dicom_interface INTERFACE cxx_std_11) 8 | target_include_directories(dicom_interface INTERFACE 9 | ${CMAKE_CURRENT_SOURCE_DIR} 10 | ) 11 | 12 | # This fixes strange whitespace errors when trying to compile against GDCM 13 | set(GDCM_USE_VTK OFF) 14 | 15 | # We need at least GDCM version 2.6 16 | find_package(GDCM 2.6 REQUIRED) 17 | 18 | target_link_libraries(dicom_interface INTERFACE gdcmMSFF) 19 | 20 | # This make GDCM header files visible to rti 21 | target_include_directories(dicom_interface INTERFACE ${GDCM_INCLUDE_DIRS}) 22 | -------------------------------------------------------------------------------- /rti/topas/tutorial/QA_view.txt: -------------------------------------------------------------------------------- 1 | includeFile = QA.txt 2 | 3 | Ts/PauseBeforeSequence = "True" 4 | Ts/PauseBeforeQuit = "True" 5 | 6 | d:Gr/MyOGLb/Theta = 10. deg 7 | d:Gr/MyOGLb/Phi = 50. deg 8 | b:Gr/MyOGLb/IncludeTrajectories = "t" 9 | 10 | s:Gr/MyOGLb/Type = "OpenGL" 11 | i:Gr/MyOGLb/WindowSizeX = 1000 12 | i:Gr/MyOGLb/WindowSizeY = 800 13 | i:Gr/MyOGLb/WindowPosX = 0 14 | i:Gr/MyOGLb/WindowPosY = 600 15 | s:Gr/MyOGLb/ColorBy = "particletype" 16 | b:Gr/MyOGLb/IncludeAxes = "true" 17 | s:Gr/MyOGLb/AxesComponent = "World" 18 | d:Gr/MyOGLb/AxesSize = 20.0 cm 19 | u:Gr/MyOGLb/Zoom = 1 20 | s:Gr/MyOGLb/Projection = "Perspective" 21 | d:Gr/MyOGLb/PerspectiveAngle = 10.0 deg 22 | 23 | #b:Ts/UseQt = "T" 24 | -------------------------------------------------------------------------------- /rti/topas/tutorial/beam_view.txt: -------------------------------------------------------------------------------- 1 | includeFile = beam.txt 2 | 3 | Ts/PauseBeforeSequence = "True" 4 | Ts/PauseBeforeQuit = "True" 5 | 6 | d:Gr/MyOGLb/Theta = 10. deg 7 | d:Gr/MyOGLb/Phi = 50. deg 8 | b:Gr/MyOGLb/IncludeTrajectories = "t" 9 | 10 | s:Gr/MyOGLb/Type = "OpenGL" 11 | i:Gr/MyOGLb/WindowSizeX = 1000 12 | i:Gr/MyOGLb/WindowSizeY = 800 13 | i:Gr/MyOGLb/WindowPosX = 0 14 | i:Gr/MyOGLb/WindowPosY = 600 15 | s:Gr/MyOGLb/ColorBy = "particletype" 16 | b:Gr/MyOGLb/IncludeAxes = "true" 17 | s:Gr/MyOGLb/AxesComponent = "World" 18 | d:Gr/MyOGLb/AxesSize = 20.0 cm 19 | u:Gr/MyOGLb/Zoom = 1 20 | s:Gr/MyOGLb/Projection = "Perspective" 21 | d:Gr/MyOGLb/PerspectiveAngle = 10.0 deg 22 | 23 | #b:Ts/UseQt = "T" 24 | -------------------------------------------------------------------------------- /rti/base/rti_beam_module_rt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_BEAM_MODULE_RT_H 2 | #define RTI_BEAM_MODULE_RT_H 3 | 4 | 5 | /// \file 6 | /// Interprets DICOM-RT (photon and electron) beam module 7 | /// \see http://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.8.html#sect_C.8.8.14 for RT Plan 8 | /// \note no plans to implement yet (July 2019). 9 | 10 | #include 11 | 12 | namespace rti { 13 | 14 | /// class beam_module_rt 15 | class beam_module_rt : public beam_module{ 16 | public: 17 | beam_module_rt( 18 | const rti::dataset* d, 19 | rti::modality_type m) 20 | :beam_module(d,m) 21 | {;} 22 | ~beam_module_rt(){;} 23 | 24 | }; 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /rti/topas/tutorial/plan_hu_view.txt: -------------------------------------------------------------------------------- 1 | includeFile = plan_hu.txt 2 | 3 | Ts/PauseBeforeSequence = "True" 4 | Ts/PauseBeforeQuit = "True" 5 | 6 | d:Gr/MyOGLb/Theta = 10. deg 7 | d:Gr/MyOGLb/Phi = 50. deg 8 | b:Gr/MyOGLb/IncludeTrajectories = "t" 9 | 10 | s:Gr/MyOGLb/Type = "OpenGL" 11 | i:Gr/MyOGLb/WindowSizeX = 1000 12 | i:Gr/MyOGLb/WindowSizeY = 800 13 | i:Gr/MyOGLb/WindowPosX = 0 14 | i:Gr/MyOGLb/WindowPosY = 600 15 | s:Gr/MyOGLb/ColorBy = "particletype" 16 | b:Gr/MyOGLb/IncludeAxes = "true" 17 | s:Gr/MyOGLb/AxesComponent = "World" 18 | d:Gr/MyOGLb/AxesSize = 20.0 cm 19 | u:Gr/MyOGLb/Zoom = 1 20 | s:Gr/MyOGLb/Projection = "Perspective" 21 | d:Gr/MyOGLb/PerspectiveAngle = 10.0 deg 22 | 23 | #b:Ts/UseQt = "T" 24 | -------------------------------------------------------------------------------- /rti/topas/tutorial/view.txt: -------------------------------------------------------------------------------- 1 | #includeFile = beam.txt 2 | #includeFile = QA_tutorial.txt 3 | #includeFile = plan_tutorial.txt 4 | 5 | Ts/PauseBeforeSequence = "True" 6 | Ts/PauseBeforeQuit = "True" 7 | 8 | d:Gr/MyOGLb/Theta = 10. deg 9 | d:Gr/MyOGLb/Phi = 50. deg 10 | b:Gr/MyOGLb/IncludeTrajectories = "t" 11 | 12 | s:Gr/MyOGLb/Type = "OpenGL" 13 | i:Gr/MyOGLb/WindowSizeX = 1000 14 | i:Gr/MyOGLb/WindowSizeY = 800 15 | i:Gr/MyOGLb/WindowPosX = 0 16 | i:Gr/MyOGLb/WindowPosY = 600 17 | s:Gr/MyOGLb/ColorBy = "particletype" 18 | b:Gr/MyOGLb/IncludeAxes = "true" 19 | s:Gr/MyOGLb/AxesComponent = "World" 20 | d:Gr/MyOGLb/AxesSize = 20.0 cm 21 | u:Gr/MyOGLb/Zoom = 1 22 | s:Gr/MyOGLb/Projection = "Perspective" 23 | d:Gr/MyOGLb/PerspectiveAngle = 10.0 deg 24 | 25 | #b:Ts/UseQt = "T" 26 | -------------------------------------------------------------------------------- /rti/treatment_machines/rbe/rbe1p1.table: -------------------------------------------------------------------------------- 1 | [geometry] 2 | # key value1 value2 3 | SAD(mm) 1340 1720 4 | #rangeshifter(mm) 200 200 5 | rangeshifter(mm) 80 0 #circle 6 | rangeshifter_snout_gap(mm) 17 7 | #rangeshifter_wet 1.15 8 | #aperture(mm) 100 150 9 | aperture(mm) 70 0 #circle 10 | 11 | [rangeshifter_thickness] 12 | #otherwise we expect the thickness is specified in WET 13 | "30mm" 30 14 | "40mm" 40 15 | "50mm" 50 16 | "60mm" 60 17 | "70mm" 70 18 | 19 | [spot] 20 | # Nominal Energy (MeV), Energy(MeV), Energy Spread (MeV), x (mm), y (mm), xp (rad), yp (rad), ratio 21 | 60.0 60.0 0.0 0.8 0.7 0.0 0.0 1.0 22 | 250.0 250.0 0.0 0.5 0.0 0.0 0.0 1.0 23 | 24 | [time] 25 | # key value 26 | E(sec) 2 27 | I(nA) 2 28 | dT_up(ms) 3 29 | dT_down(ms) 3 30 | set_x(ms) 0.005 31 | set_y(ms) 0.005 32 | velocity_x(m/sec) 30 33 | velocity_y(m/sec) 3 34 | -------------------------------------------------------------------------------- /rti/topas/rtion/TsRTIonSourceGenerator.hh: -------------------------------------------------------------------------------- 1 | //RTI beamlet for spot-scanning, rasterscanning, continuous scanning 2 | #ifndef TsRTIonSourceGenerator_hh 3 | #define TsRTIonSourceGenerator_hh 4 | 5 | #include "globals.hh" 6 | 7 | #include "TsVGenerator.hh" 8 | #include "TsPrimaryParticle.hh" 9 | 10 | #include 11 | 12 | class TsParameterManager; 13 | class TsGeometryManager ; 14 | class TsGeneratorManager; 15 | 16 | class TsRTIonSourceGenerator : public TsVGenerator { 17 | protected: 18 | std::queue* fParticleBuffer; 19 | void ResolveParameters(); 20 | void GeneratePrimaries(G4Event* ); 21 | 22 | public: 23 | TsRTIonSourceGenerator( 24 | TsParameterManager* pM, 25 | TsGeometryManager* gM, 26 | TsGeneratorManager* psM, 27 | G4String sourceName); 28 | 29 | ~TsRTIonSourceGenerator(); 30 | 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /rti/base/rti_common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_COMMON_HPP 2 | #define RTI_COMMON_HPP 3 | 4 | /// \file 5 | /// 6 | /// A header including CUDA related headers and functions 7 | 8 | #if defined(__CUDACC__) 9 | 10 | # include 11 | # include 12 | # include 13 | //#include "helper/helper_cuda.h" 14 | //#include "helper/helper_math.h" 15 | # include 16 | # include 17 | 18 | # define CUDA_HOST_DEVICE __host__ __device__ 19 | # define CUDA_HOST __host__ 20 | # define CUDA_DEVICE __device__ 21 | 22 | //# define rti_sqrt(__CUDACC__) 23 | // 24 | //sqrtf : for float, sqrtg: for double 25 | //T norm()const{return sqrtf(x*x+y*y+z*z);} 26 | //#else 27 | //T norm()const{return std::sqrt(x*x+y*y+z*z);} 28 | //#endif 29 | 30 | 31 | #else 32 | 33 | # define CUDA_HOST_DEVICE 34 | # define CUDA_HOST 35 | # define CUDA_DEVICE 36 | 37 | 38 | #endif 39 | 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /rti/base/rti_beam_module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_BEAM_MODULE_H 2 | #define RTI_BEAM_MODULE_H 3 | 4 | /// \file 5 | /// 6 | /// Top abstraction to interpret DICOM beam modules, RT and RT-Ion. 7 | 8 | #include 9 | 10 | namespace rti { 11 | 12 | /// \class beam_module 13 | /// 14 | /// A class that interprets IonControlPoints and converts fluence_map to be actually delivered. 15 | /// beam_module : provides overall interface to MC engine 16 | /// beam_module_rt : photon/electron -> DYNAMIC, STATIC 17 | /// beam_module_rtion : proton/particles -> UNIFORM, MODULATED, MODULATED_SPEC 18 | class beam_module { 19 | public: 20 | protected: 21 | const rti::dataset* ds_; ///< Item of IonBeamSequence 22 | const rti::modality_type modality_ ; 23 | 24 | public: 25 | beam_module(const rti::dataset* d, 26 | rti::modality_type mod) 27 | :ds_(d), modality_(mod) 28 | {;} 29 | 30 | ~beam_module(){;} 31 | 32 | virtual void dump() const {;} 33 | 34 | 35 | }; 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /rti/test/session/pbs_generic.table: -------------------------------------------------------------------------------- 1 | [geometry] 2 | # key value1 value2 3 | SAD(mm) 1340 1720 4 | rangeshifter(mm) 300 400 5 | #rangeshifter(mm) 80 0 #circle 6 | rangeshifter_snout_gap(mm) 17 7 | #rangeshifter_wet 1.15 8 | aperture(mm) 30 40 9 | #aperture(mm) 70 0 #circle 10 | 11 | [rangeshifter_thickness] 12 | #otherwise we expect the thickness is specified in WET 13 | "RS 30mm" 30 14 | "RS 40mm" 40 15 | "RS 50mm" 50 16 | "RS 60mm" 60 17 | "RS 70mm" 70 18 | "RS 80mm" 80 19 | "RS 30 mm" 30 20 | "RS 40 mm" 40 21 | "RS 50 mm" 50 22 | "RS 60 mm" 60 23 | "RS 70 mm" 70 24 | "RS 80 mm" 80 25 | "30" 30 26 | "40" 40 27 | "50" 50 28 | "60" 60 29 | "70" 70 30 | "80" 80 31 | 32 | [spot] 33 | # Nominal Energy (MeV), Energy(MeV), Energy Spread (MeV), x (cm), y (cm), xp (rad), yp (rad), ratio 34 | 60.0 60.0 0.0 0.0 0.0 0.0 0.0 1.0 35 | 250.0 250.0 0.0 0.0 0.0 0.0 0.0 1.0 36 | 37 | [time] 38 | # key value 39 | E(sec) 2 40 | I(nA) 2 41 | dT_up(ms) 3 42 | dT_down(ms) 3 43 | set_x(ms) 0.005 44 | set_y(ms) 0.005 45 | velocity_x(m/sec) 30 46 | velocity_y(m/sec) 3 47 | -------------------------------------------------------------------------------- /rti/base/rti_vertex.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_VERTEX_HPP 2 | #define RTI_VERTEX_HPP 3 | 4 | #include 5 | 6 | namespace rti{ 7 | 8 | ///< Particle properties at a position 9 | ///< Physics will propose next vertex 10 | ///< Geometry will propose next vertex 11 | ///< Step limiter will propose next vertex 12 | ///< Magnetic field will propose next vertex 13 | ///< Vertex doesn't include particle type 14 | template 15 | struct vertex_t 16 | { 17 | T ke {} ; //< kinetic energy 18 | vec3 pos{} ; //< position 19 | vec3 dir{} ; //< direction 20 | 21 | CUDA_HOST_DEVICE 22 | vertex_t& 23 | operator=(const vertex_t& rhs) 24 | { 25 | ke = rhs.ke ; 26 | pos = rhs.pos; 27 | dir = rhs.dir; 28 | return *this; 29 | } 30 | 31 | /// Copy assignment constructor 32 | CUDA_HOST_DEVICE 33 | vertex_t(const vertex_t& rhs) : 34 | ke (rhs.ke ), 35 | pos(rhs.pos), 36 | dir(rhs.dir) 37 | {;} 38 | 39 | CUDA_HOST_DEVICE 40 | vertex_t() 41 | {;} 42 | }; 43 | 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 topasmc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /rti/topas/tutorial/plan_tutorial.txt: -------------------------------------------------------------------------------- 1 | includeFile = plan_hu.txt 2 | 3 | 4 | # ---- TOPAS' example CT was used. Then, 5 | Ge/RTION/TransX = 0.0 mm 6 | Ge/RTION/TransY = 0.0 mm 7 | Ge/RTION/TransZ = 0.0 mm 8 | # ---- 9 | So/RTION/ShiftX = 0.0 mm 10 | So/RTION/ShiftY = 0.0 mm 11 | So/RTION/ShiftZ = 0.0 mm 12 | i:Gr/ShowOnlyOutlineIfVoxelCountExceeds = 1000000 13 | 14 | #--- physics 15 | Ph/Default/Modules = 1 "g4em-standard_opt4" 16 | 17 | #--- beamlet 18 | #iv:So/RTION/BeamletRange = 2 1 2 19 | 20 | #--- IEC2DICOM 21 | # Ge/RTION/RotIEC2DICOM = 0.0 deg 22 | # So/RTION/RotIEC2DICOM = 0.0 deg 23 | 24 | #################################################### 25 | #----------------- Scorers -------------------- 26 | #################################################### 27 | #----------------- Dose -------------------- 28 | s:Sc/DoseGrid_Dw/Quantity = "DoseToWater" 29 | s:Sc/DoseGrid_Dw/Component = "Patient/RTDoseGrid" 30 | s:Sc/DoseGrid_Dw/OutputFile = "Dw_patient" 31 | s:Sc/DoseGrid_Dw/OutputType = "binary" 32 | s:Sc/DoseGrid_Dw/IfOutputFileAlreadyExists = "OverWrite" # Exit, Overwrite or Increment 33 | b:Sc/DoseGrid_Dw/PreCalculateStoppingPowerRatios = "True" 34 | b:Sc/DoseGrid_Dw/OutputToConsole = "FALSE" 35 | 36 | #----------------- LETd -------------------- 37 | #? 38 | 39 | -------------------------------------------------------------------------------- /rti/base/rti_stopping_power.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_STOPPING_POWER_H 2 | #define RTI_STOPPING_POWER_H 3 | 4 | /// \file 5 | /// 6 | /// Stopping power interface 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace rti{ 17 | 18 | #include "rti_stopping_power.icc" 19 | 20 | /// Returns stopping power for given material and energy 21 | inline float 22 | stopping_power( 23 | float energy, 24 | const char* material="water") 25 | { 26 | if( !std::strcmp(material, "water") ){ 27 | return rti::interp_linear(icru_stopping_power_water, energy, 2); 28 | }else if( !std::strcmp(material, "air") ){ 29 | return rti::interp_linear(icru_stopping_power_air, energy, 2); 30 | } 31 | assert("Can't find given stopping power table"); 32 | return -1.0f; 33 | } 34 | 35 | /// Returns water equivalent thickness of air of pos_z (thickness) 36 | inline float 37 | wet_air( 38 | float energy, //MeV 39 | float pos_z) //cm 40 | { 41 | //density: 0.00120479 42 | 43 | return pos_z*(0.00120479)* stopping_power(energy, "air")/stopping_power(energy, "water"); 44 | } 45 | 46 | } //namespace 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /rti/topas/tutorial/QA_tutorial.txt: -------------------------------------------------------------------------------- 1 | includeFile = QA.txt 2 | 3 | # This is a file for users who want to change default settings in QA application chain 4 | 5 | # Hands on 1 ---- 6 | # Physics 7 | # Ph/Default/Modules = 1 "g4em-standard_opt4" 8 | # Ph/Default/Modules = 6 "g4em-standard_opt4" "g4h-phy_QGSP_BERT_HP" "g4decay" "g4ion-binarycascade" "g4h-elastic_HP" "g4stopping" 9 | 10 | # Hands on 2 ---- 11 | # RangeShifter On/Off 12 | # b:Ge/RTION/IncludeRangeshifterIfExist = "T" 13 | 14 | # Hands on 3 -- 15 | # Aperture On/Off 16 | # b:Ge/RTION/IncludeBlockIfExist = "T" 17 | 18 | # Hands on 4 19 | # control number of particles 20 | # particle per history 21 | # -1 : 1 history per beamlet 22 | # 1e6 : 1 history represents 1e6 protons 23 | # u:So/RTION/ParticlesPerHistory = 1e6 24 | 25 | # Hands on 5 26 | # Beamlet range 27 | # you can specify beamlet ranges to simulate 28 | # ex) follow will simulate only 1st and 2nd beamlets. 29 | # iv:So/RTION/BeamletRange = 2 1 2 30 | 31 | # Hands on 6 32 | Ge/RTION/RotGantry = 0.0 deg 33 | So/RTION/RotGantry = 0.0 deg 34 | 35 | 36 | # Hands on 7 37 | # change your output file name 38 | s:Sc/DoseGrid_Dw/OutputFile = "Dw" 39 | 40 | # Hands on 8 41 | # change machine-description-file 42 | #s:Ge/RTION/MachineName = "pbs:../../treatment_machines/rbe/rbe1p1.table" 43 | #s:So/RTION/MachineName = "pbs:../../treatment_machines/rbe/rbe1p1.table" 44 | 45 | -------------------------------------------------------------------------------- /rti/base/rti_rangeshifter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_RANGESHIFTER_H 2 | #define RTI_RANGESHIFTER_H 3 | 4 | /// \file 5 | /// 6 | /// RT-Ion geometry for rangeshifter 7 | 8 | #include 9 | 10 | namespace rti{ 11 | 12 | /// \class rangeshifter 13 | /// supports box and cylinder type rangeshifter 14 | /// \note only one material 15 | class rangeshifter : public geometry{ 16 | 17 | public: 18 | 19 | const bool is_rectangle; ///< type of volume 20 | const rti::vec3 volume; ///< volume dimension 21 | 22 | /// Constructor 23 | rangeshifter( 24 | rti::vec3& v, ///< x,y,z or r, theta, thickness 25 | rti::vec3& p, ///< position 26 | rti::mat3x3& r, ///< rotation matrix 27 | bool is_rect=true) 28 | : geometry(p, r, rti::geometry_type::RANGESHIFTER), 29 | is_rectangle(is_rect), 30 | volume(v) 31 | {;} 32 | 33 | /// Copy constructor 34 | rangeshifter(const rti::rangeshifter& rhs) 35 | : geometry(rhs.pos, rhs.rot, rhs.geotype), 36 | is_rectangle(rhs.is_rectangle), 37 | volume(rhs.volume) 38 | {;} 39 | 40 | /// Destructor 41 | ~rangeshifter(){;} 42 | 43 | /// Assignment operator 44 | const rangeshifter& 45 | operator= 46 | (const rti::rangeshifter& rhs) 47 | { 48 | return rhs; 49 | } 50 | 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /rti/base/distributions/rti_const_1d.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_CONST1D_H 2 | #define RTI_CONST1D_H 3 | 4 | /// \file 5 | /// 6 | /// Distribution functions (meta-header file for all distributions) 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | namespace rti{ 24 | 25 | /// \class const_1d 26 | /// 27 | /// 1-dimensional const pdf. 28 | /// \tparam T type of return value 29 | /// \note sigam values are ignored 30 | template 31 | class const_1d : public pdf_Md { 32 | 33 | public: 34 | 35 | /// Constructor 36 | CUDA_HOST_DEVICE 37 | const_1d( 38 | std::array& m_, 39 | std::array& s_) 40 | : pdf_Md(m_,s_) 41 | {;} 42 | 43 | /// Constructor 44 | CUDA_HOST_DEVICE 45 | const_1d( 46 | const std::array& m_, 47 | const std::array &s_) 48 | : pdf_Md(m_,s_) 49 | {;} 50 | 51 | /// Returns mean_ 52 | CUDA_HOST_DEVICE 53 | virtual 54 | std::array 55 | operator()(void){ 56 | return pdf_Md::mean_; 57 | }; 58 | 59 | }; 60 | 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /rti/base/distributions/rti_norm_1d.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RTI_NORM_1D_H 3 | #define RTI_NORM_1D_H 4 | 5 | /// \file 6 | /// 7 | /// Distribution functions for 1D normal distribution 8 | 9 | 10 | #include 11 | 12 | namespace rti{ 13 | /// \class norm_1d 14 | /// 15 | /// 1-dimensional normal pdf. 16 | /// \tparam T type of return value 17 | /// \note in future, the randome engine will be relocated. 18 | template 19 | class norm_1d : public pdf_Md { 20 | public: 21 | 22 | std::default_random_engine gen_ ; ///< C++ random engine 23 | std::normal_distribution func_; ///< C++ distribution function 24 | 25 | /// Constructor to copy mean and sigma and initialize normal_distributions 26 | CUDA_HOST_DEVICE 27 | norm_1d( 28 | std::array& m_, 29 | std::array& s_) 30 | : pdf_Md(m_,s_) 31 | { 32 | #if !defined(__CUDACC__) 33 | func_ = std::normal_distribution(m_[0], s_[0]); 34 | #endif 35 | } 36 | 37 | /// Constructor to copy mean and sigma 38 | CUDA_HOST_DEVICE 39 | norm_1d( 40 | const std::array& m_, 41 | const std::array &s_) 42 | : pdf_Md(m_,s_) 43 | { 44 | #if !defined(__CUDACC__) 45 | func_ = std::normal_distribution(m_[0], s_[0]); 46 | #endif 47 | } 48 | 49 | /// Returns value sampled from normal distribution 50 | CUDA_HOST_DEVICE 51 | virtual 52 | std::array 53 | operator()(void){ 54 | return {func_(gen_)}; 55 | }; 56 | 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /rti/test/session/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.11) 2 | project (session) 3 | 4 | #find_package (GDCM REQUIRED) 5 | #include (${GDCM_USE_FILE}) 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | set(CMAKE_CXX_EXTENSIONS ON) 10 | 11 | #file(GLOB gdcmlibs "${GDCM_LIBRARY_DIRS}/*.so*" "${GDCM_LIBRARY_DIRS}/*.a" "${GDCM_LIBRARY_DIRS}/*.dylib") 12 | #file(GLOB excludegdcmlibs "${GDCM_LIBRARY_DIRS}/libgdcmMEXD.*" "${GDCM_LIBRARY_DIRS}/libsocketxx.*") 13 | 14 | find_library (PATHS /opt/sw/topas/3.9.0/Frameworks/ ) 15 | 16 | if(APPLE) 17 | find_library(COREFOUNDATION_LIBRARY CoreFoundation ) 18 | endif() 19 | 20 | include_directories ( 21 | ${PROJECT_SOURCE_DIR} 22 | /opt/sw/dicom-interface/git.public.20221230/gdcm-2.6 23 | ../../../ 24 | ) 25 | 26 | link_directories ( 27 | ${PROJECT_SOURCE_DIR} 28 | /opt/sw/topas/3.9.0/Frameworks/ 29 | ) 30 | 31 | add_executable(treatment_session treatment_session.cpp) 32 | add_executable(smc_linescan smc_linescan.cpp) 33 | 34 | #install(PROGRAMS treatment_session DESTINATION .) 35 | 36 | set (GDCM_Libs 37 | gdcmMSFF 38 | gdcmDICT 39 | gdcmIOD 40 | gdcmexpat 41 | gdcmDSED 42 | gdcmCommon 43 | gdcmzlib 44 | gdcmjpeg8 45 | gdcmjpeg12 46 | gdcmjpeg16 47 | gdcmopenjpeg 48 | gdcmcharls 49 | gdcmuuid) 50 | 51 | 52 | target_link_libraries(treatment_session 53 | ${COREFOUNDATION_LIBRARY} 54 | ${GDCM_Libs} 55 | ) 56 | 57 | target_link_libraries(smc_linescan 58 | ${COREFOUNDATION_LIBRARY} 59 | ${GDCM_Libs} 60 | ) 61 | 62 | 63 | -------------------------------------------------------------------------------- /rti/base/distributions/rti_uni_1d.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RTI_UNI_1D_H 3 | #define RTI_UNI_1D_H 4 | 5 | /// \file 6 | /// 7 | /// Distribution functions (meta-header file for all distributions) 8 | 9 | #include 10 | 11 | namespace rti{ 12 | /// \class uni_1d 13 | /// 14 | /// 1-dimensional uniform pdf. 15 | /// \tparam T type of return value 16 | template 17 | class uni_1d : public pdf_Md { 18 | public: 19 | 20 | std::default_random_engine gen_ ; ///< C++ random engine 21 | std::uniform_real_distribution func_ ; ///< C++ distribution function 22 | 23 | /// Constructor to copy mean and sigma and initialize uniform_distributions 24 | /// In this pdf, mean[0] and sigma[0] will be used for ranges 25 | /// e.g., a random variable will be sampled from mean[0] and sigma[0] 26 | CUDA_HOST_DEVICE 27 | uni_1d( 28 | std::array& m, 29 | std::array& s) 30 | : pdf_Md(m,s) 31 | { 32 | #if !defined(__CUDACC__) 33 | func_ = std::uniform_real_distribution(m[0], s[0]); 34 | #endif 35 | } 36 | 37 | /// Constructor to copy mean and sigma and initialize uniform_distributions 38 | CUDA_HOST_DEVICE 39 | uni_1d( 40 | const std::array& m, 41 | const std::array& s) 42 | : pdf_Md(m,s) 43 | { 44 | #if !defined(__CUDACC__) 45 | func_ = std::uniform_real_distribution(m[0], s[0]); 46 | #endif 47 | } 48 | 49 | /// Returns value sampled from 1-d uniform distribution 50 | CUDA_HOST_DEVICE 51 | virtual 52 | std::array 53 | operator()(void){ 54 | return {func_(gen_)}; 55 | }; 56 | 57 | }; 58 | 59 | } 60 | #endif -------------------------------------------------------------------------------- /rti/base/rti_beamline.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_BEAMLINE_H 2 | #define RTI_BEAMLINE_H 3 | 4 | /// \file 5 | /// 6 | /// A beamline is a collection of physical components in the beamline 7 | 8 | #include 9 | #include 10 | 11 | namespace rti{ 12 | 13 | /// \class beamline 14 | /// 15 | /// \tparam T type of units 16 | /// \note we may not need this class if this is a just container for geometries. 17 | /// Will be determined later. 18 | template 19 | class beamline { 20 | public: 21 | 22 | protected: 23 | 24 | /// A container for components 25 | std::vector geometries_; 26 | 27 | /// A coordinate transform. 28 | /// \note not sure we need this in future. 29 | rti::coordinate_transform p_coord_; 30 | 31 | public: 32 | 33 | /// An empty constructor 34 | beamline(){;} 35 | 36 | /// Clear all geometries in the vector 37 | ~beamline(){ 38 | 39 | geometries_.clear(); 40 | } 41 | 42 | /// Add new geometry to the container. 43 | void 44 | append_geometry( 45 | rti::geometry* geo) 46 | { 47 | geometries_.push_back(geo); 48 | } 49 | 50 | /// Returns geometry container (const reference) 51 | const std::vector& 52 | get_geometries(){ 53 | return geometries_; 54 | } 55 | 56 | /* 57 | void dump(){ 58 | for(auto i : rotation_){ 59 | std::cout< 9 | 10 | namespace rti{ 11 | 12 | /// \class aperture 13 | /// \brief A aperture class 14 | 15 | class aperture : public geometry{ 16 | public: 17 | /// whehter aperture shape is box or cylinder type 18 | bool is_rectangle ; 19 | 20 | /// aperture dimension, (Lx, Ly, Lz) for box or (R, H, dummy) for cylinder 21 | const rti::vec3 volume; 22 | 23 | /// X-Y opening points. Divergence is not considered. 24 | const std::vector>> block_data; 25 | 26 | public: 27 | 28 | /// Creates an aperture 29 | /// \param xypts a set of (x,y) points. 30 | /// \param v a volume, e.g., (Lx,Ly,Lz) or (R, thickness, ignored). 31 | /// \param p a center position of the aperture. 32 | /// \param is_rect tells whether aperture is box shape or cylinder shape. 33 | aperture( 34 | std::vector>> xypts, 35 | rti::vec3& v, 36 | rti::vec3& p, 37 | rti::mat3x3& r, 38 | bool is_rect = true) 39 | : geometry (p, r, rti::geometry_type::BLOCK), 40 | is_rectangle(is_rect), 41 | volume(v), 42 | block_data(xypts) 43 | {;} 44 | 45 | /// Creates a copy from an existing aperture 46 | aperture( 47 | const rti::aperture& rhs) 48 | : geometry(rhs.pos, rhs.rot, rhs.geotype), 49 | is_rectangle(rhs.is_rectangle), 50 | volume(rhs.volume), 51 | block_data(rhs.block_data) 52 | {;} 53 | 54 | /// Destructor 55 | ~aperture(){;} 56 | 57 | /// Assignment operator 58 | const aperture& 59 | operator= 60 | (const rti::aperture& rhs) 61 | { 62 | return rhs; 63 | } 64 | 65 | }; 66 | 67 | 68 | } 69 | #endif 70 | -------------------------------------------------------------------------------- /rti/base/distributions/rti_pdfMd.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RTI_PDFMD_H 3 | #define RTI_PDFMD_H 4 | 5 | /// \file 6 | /// 7 | /// Distribution functions (meta-header file for all distributions) 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | 23 | namespace rti{ 24 | 25 | /// \class pdf_Md 26 | /// 27 | /// M-dimensional probability distribution function (pdf). 28 | /// \tparam T type of return value 29 | /// \tparam M size of return values 30 | /// pure virtual class 31 | template 32 | class pdf_Md{ 33 | protected: 34 | std::array mean_ ; ///< M means 35 | std::array sigma_ ; ///< M sigmas 36 | public: 37 | 38 | /// Constructor to fill mean_ and sigma_ 39 | CUDA_HOST_DEVICE 40 | pdf_Md( 41 | std::array& m_, 42 | std::array& s_) 43 | { 44 | for(std::size_t i=0; i < M ; ++i){ 45 | mean_[i] = m_[i]; 46 | sigma_[i] = s_[i]; 47 | } 48 | } 49 | 50 | /// Constructor to fill const mean_ and const sigma_ 51 | CUDA_HOST_DEVICE 52 | pdf_Md( 53 | const std::array& m_, 54 | const std::array& s_) 55 | { 56 | for(std::size_t i=0; i < M ; ++i){ 57 | mean_[i] = m_[i]; 58 | sigma_[i] = s_[i]; 59 | } 60 | } 61 | 62 | /// Prints out means and sigmas 63 | CUDA_HOST_DEVICE 64 | void 65 | dump(){ 66 | for(size_t i=0 ; i < M ; ++i) 67 | std::cout<< "mean: " << mean_[i] << ", sigma: " << sigma_[i] << std::endl; 68 | } 69 | 70 | /// Destructor 71 | CUDA_HOST_DEVICE 72 | ~pdf_Md(){;} 73 | 74 | 75 | /// '()' operator overloading to act like a function. 76 | CUDA_HOST_DEVICE 77 | virtual 78 | std::array 79 | operator()(void) = 0; 80 | 81 | }; 82 | 83 | 84 | } 85 | 86 | #endif 87 | 88 | -------------------------------------------------------------------------------- /rti/topas/rtion/TsRTIonSource.hh: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TsRTIonSource_hh 3 | #define TsRTIonSource_hh 4 | 5 | #include 6 | #include 7 | 8 | #include "G4ParticleDefinition.hh" 9 | #include "G4Proton.hh" 10 | 11 | #include "globals.hh" 12 | 13 | #include "TsSource.hh" 14 | #include "TsPrimaryParticle.hh" 15 | 16 | #include 17 | 18 | class TsRTIonSource : public TsSource { 19 | protected: 20 | 21 | G4ParticleDefinition* particle_definition_ ; 22 | 23 | std::unique_ptr> rti_session_ ; 24 | 25 | rti::beamsource beam_source_; 26 | 27 | //current can be replaced by start. however, we keep this. 28 | struct { 29 | int start; 30 | int stop ; 31 | int current; //beamlet id, where all histories to this beamlet were passed 32 | long int history; //number of histories to be passed to generaters so far. 33 | } counter_ ; 34 | 35 | void ResolveParameters(); 36 | 37 | //Get corrdinate system first 38 | rti::coordinate_transform rt_coordinate; 39 | 40 | void ExportDICOMCoordinateToParameters( 41 | rti::coordinate_transform& p 42 | ); 43 | 44 | void 45 | Wrap3Vector( 46 | rti::vec3 vec, 47 | const char* name, 48 | const char* unit=" mm" 49 | ); 50 | 51 | void 52 | Wrap1Vector( 53 | float value, 54 | const char* name, 55 | const char* unit=" deg" 56 | ); 57 | 58 | public: 59 | TsRTIonSource(TsParameterManager* pM, TsSourceManager* psM, G4String sourceName); 60 | ~TsRTIonSource(); 61 | 62 | //function object, which will be coupled one of 63 | // : ReadHistoriesPerBeamlet for spot-scanning 64 | // : ReadHistoriesPerBCM for IBA's DS 65 | std::function*)> ReadHistories; 66 | 67 | //G4bool ReadSomeDataFrombeam(std::queue* ); 68 | G4bool ReadHistoriesPerBeamlet(std::queue* ); 69 | 70 | void UpdateForNewRun(G4bool){;} 71 | 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /rti/topas/rtion/TsRTIonSourceGenerator.cc: -------------------------------------------------------------------------------- 1 | // Particle Generator for TsRTIonSource 2 | // This code implementation is the intellectual property of the MGH. 3 | // this is an user extension for RT-Ion plan (RTIP) and beam treatment record (RTIBTR) 4 | // by Jungwook Shin jshin13@mgh.harvard.edu 5 | 6 | #include 7 | 8 | //#include 9 | //#include 10 | //#include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "G4SystemOfUnits.hh" 19 | 20 | //Headers for TOPAS 21 | #include "TsParameterManager.hh" 22 | 23 | //Headers for extension 24 | #include "TsRTIonSource.hh" 25 | #include "TsRTIonSourceGenerator.hh" 26 | 27 | 28 | TsRTIonSourceGenerator::TsRTIonSourceGenerator( 29 | TsParameterManager* pM, 30 | TsGeometryManager* gM, 31 | TsGeneratorManager* psM, 32 | G4String n) 33 | :TsVGenerator(pM, gM, psM,n) 34 | { 35 | fParticleBuffer = new std::queue; 36 | this->ResolveParameters(); 37 | } 38 | 39 | TsRTIonSourceGenerator::~TsRTIonSourceGenerator() {;} 40 | 41 | void TsRTIonSourceGenerator::ResolveParameters(){ 42 | //TsVGenerator::ResolveParameters(); 43 | //TODO: beam number? or beam name?, e.g., beam number tentatively 44 | CacheGeometryPointers(); 45 | } 46 | 47 | void TsRTIonSourceGenerator::GeneratePrimaries(G4Event *evt){ 48 | 49 | if(CurrentSourceHasGeneratedEnough()) return; 50 | 51 | if (fParticleBuffer->empty()){ 52 | ((TsRTIonSource*) fPs)->ReadHistories(fParticleBuffer); 53 | } 54 | 55 | //IMPORTANT: assign histories from the buffer to single event. 56 | //this reduce overhead to create G4Event per history 57 | while( !fParticleBuffer->empty() ){ 58 | 59 | TsPrimaryParticle p = fParticleBuffer->front(); 60 | 61 | //TransformPrimaryForComponent is a part of topas version higher 3.1 62 | //TransformPrimaryForComponent(&p); 63 | 64 | GenerateOnePrimary(evt, p); //in this loop, topas add p to vertex 65 | AddPrimariesToEvent(evt); 66 | fParticleBuffer->pop(); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /rti/base/rti_geometry.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_GEOMETRY_HPP 2 | #define RTI_GEOMETRY_HPP 3 | 4 | /// \file 5 | /// 6 | /// RT-Ion geometry 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace rti{ 17 | 18 | /// Enumerate for geometry type 19 | /// \note many of these are not supported yet. 20 | typedef enum{ 21 | SNOUT , 22 | RANGESHIFTER , 23 | COMPENSATOR , 24 | BLOCK , 25 | BOLI , 26 | WEDGE , 27 | TRANSFORM , 28 | MLC , 29 | PATIENT , 30 | DOSEGRID , 31 | UNKNOWN1 , 32 | UNKNOWN2 , 33 | UNKNOWN3 , 34 | UNKNOWN4 35 | } geometry_type; 36 | 37 | 38 | /// \class geometry 39 | /// Top abstraction class so it has only translation and rotational movement. 40 | class geometry { 41 | 42 | public: 43 | 44 | const rti::vec3 pos ; ///< position, public access 45 | const rti::mat3x3 rot ; ///< rotation, public access 46 | const geometry_type geotype ; ///< geometry type, public access 47 | 48 | /// Constructor 49 | /// \param p_xyz position vector 50 | /// \param rot_xyz rotation matrix 3x3 51 | geometry( 52 | rti::vec3& p_xyz, 53 | rti::mat3x3& rot_xyz, 54 | rti::geometry_type t) 55 | : pos(p_xyz), 56 | rot(rot_xyz), 57 | geotype(t) 58 | {;} 59 | 60 | /// Constructor 61 | /// \param p_xyz position vector 62 | /// \param rot_xyz rotation matrix 3x3 63 | geometry( 64 | const rti::vec3& p_xyz, 65 | const rti::mat3x3& rot_xyz, 66 | const rti::geometry_type t) 67 | : pos(p_xyz), 68 | rot(rot_xyz), 69 | geotype(t) 70 | {;} 71 | 72 | /// Copy constructor 73 | geometry(const geometry& rhs) 74 | : pos(rhs.pos), 75 | rot(rhs.rot) , 76 | geotype(rhs.geotype) 77 | {;} 78 | 79 | /// Assignment operator 80 | const geometry& 81 | operator= 82 | (const rti::geometry& rhs) 83 | { 84 | return rhs; 85 | } 86 | 87 | /// Destructor 88 | ~geometry(){;} 89 | 90 | /// Prints geometry information 91 | virtual void 92 | dump() 93 | const 94 | {;} 95 | 96 | }; 97 | 98 | 99 | } 100 | #endif 101 | -------------------------------------------------------------------------------- /rti/topas/tutorial/QA.txt: -------------------------------------------------------------------------------- 1 | includeFile = beam.txt 2 | 3 | #################################################### 4 | #----------------- World -------------------- 5 | #################################################### 6 | Ge/World/HLX = 45.0 cm 7 | Ge/World/HLY = 45.0 cm 8 | Ge/World/HLZ = 45.0 cm 9 | 10 | #################################################### 11 | #----------------- RTIonComponent ------------------ 12 | #################################################### 13 | # Nothing to do 14 | 15 | #################################################### 16 | #----------------- RTIonSource -------------------- 17 | #################################################### 18 | # Nothing to do 19 | 20 | #################################################### 21 | #----------------- Waterphantom -------------------- 22 | #################################################### 23 | # Initially waterphantom center is iso 24 | s:Ge/WaterPhantomTop/Type = "Group" 25 | s:Ge/WaterPhantomTop/Parent = "IEC_F" 26 | d:Ge/WaterPhantomTop/TransX = 0 mm 27 | d:Ge/WaterPhantomTop/TransY = 0 mm 28 | d:Ge/WaterPhantomTop/TransZ = 0.0 cm 29 | d:Ge/WaterPhantomTop/RotX = 0 deg 30 | d:Ge/WaterPhantomTop/RotY = 0 deg 31 | d:Ge/WaterPhantomTop/RotZ = 0 deg 32 | 33 | #--- Water phantom target 34 | s:Ge/WaterPhantom/Type="TsBox" 35 | s:Ge/WaterPhantom/Parent="WaterPhantomTop" 36 | #Water: I-value 75 eV 37 | #G4_Water: I-value: 78, ICRU 75 +- 3 eV 38 | s:Ge/WaterPhantom/Material="G4_WATER" 39 | d:Ge/WaterPhantom/HLX= 5.0 cm 40 | d:Ge/WaterPhantom/HLY= 5.0 cm 41 | d:Ge/WaterPhantom/HLZ= 10 cm 42 | d:Ge/WaterPhantom/TransX = 0. cm 43 | d:Ge/WaterPhantom/TransY = 0. cm 44 | d:Ge/WaterPhantom/TransZ = Ge/WaterPhantom/HLZ cm * -1.0 45 | d:Ge/WaterPhantom/RotX = 0. deg 46 | d:Ge/WaterPhantom/RotY = 0. deg 47 | d:Ge/WaterPhantom/RotZ = 0. deg 48 | s:Ge/WaterPhantom/Color = "blue" 49 | 50 | i:Ge/WaterPhantom/XBins = 50 #2.0 mm 51 | i:Ge/WaterPhantom/YBins = 50 #2.0 mm 52 | i:Ge/WaterPhantom/ZBins = 100 #2.0 mm 53 | 54 | #################################################### 55 | #----------------- Scorers -------------------- 56 | #################################################### 57 | s:Sc/DoseGrid_Dw/Quantity = "DoseToWater" 58 | s:Sc/DoseGrid_Dw/Component = "WaterPhantom" 59 | s:Sc/DoseGrid_Dw/OutputFile = "Dw" 60 | s:Sc/DoseGrid_Dw/OutputType = "binary" 61 | s:Sc/DoseGrid_Dw/IfOutputFileAlreadyExists = "OverWrite" # Exit, Overwrite or Increment 62 | b:Sc/DoseGrid_Dw/PreCalculateStoppingPowerRatios = "True" 63 | b:Sc/DoseGrid_Dw/OutputToConsole = "FALSE" 64 | -------------------------------------------------------------------------------- /rti/base/rti_beamlet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_BEAMLET_HPP 2 | #define RTI_BEAMLET_HPP 3 | 4 | /// \file 5 | /// 6 | /// A beamlet is a collection of distributions of a beam model and 7 | /// provides phase-space variables, e, x, x', y, y', z, z'. 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace rti{ 22 | 23 | /// \class beamlet 24 | /// Represents a beamlet of a treatment field. 25 | /// Beamlet can be a a whole field (maybe double scattering) or a pencil beam of IMPT 26 | /// Beamlet consists of 4 distributions 27 | /// 1. energy samples energy of beam 28 | /// 2. fluence samples x, x', y, y', z, z' 29 | /// 3. mapping coordinate system 30 | /// \tparam T for types for return values by the distributions 31 | /// \note 32 | /// This beamlet may be called CPU and GPU. 33 | template 34 | class beamlet { 35 | protected: 36 | 37 | /// Distribution function of energy, 1-D distribution 38 | rti::pdf_Md* energy = nullptr; 39 | 40 | /// Distribution function for fluence, 6-D distribution 41 | rti::pdf_Md* fluence = nullptr; 42 | 43 | /// Coordinate transform to map local generation to patient or treatment coordination. 44 | coordinate_transform p_coord; 45 | 46 | public: 47 | 48 | /// Construct a beam from the distributions of energy and fluence. 49 | CUDA_HOST_DEVICE 50 | beamlet( 51 | rti::pdf_Md* e, 52 | rti::pdf_Md* f 53 | ):energy(e), 54 | fluence(f) 55 | {;} 56 | 57 | /// Destructor 58 | /// \note Do we need to de-allocate the energy and fluence distribution here? 59 | CUDA_HOST_DEVICE 60 | beamlet(){;} 61 | 62 | /// Creates a copy beamlet from assignment operator 63 | CUDA_HOST_DEVICE 64 | beamlet(const beamlet& rhs) : 65 | energy (rhs.energy ), 66 | fluence(rhs.fluence), 67 | p_coord(rhs.p_coord) 68 | {;} 69 | 70 | /// Set coordinate transform from outside. 71 | /// \param p coordinate_transform consisting of translation and rotation 72 | CUDA_HOST_DEVICE 73 | void 74 | set_coordinate_transform( 75 | coordinate_transform p) 76 | {p_coord = p;} 77 | 78 | /// Samples energy, position, direction of a history 79 | /// \param no 80 | /// \return a tuple of energy, position(vec3), direction (vec3) 81 | CUDA_HOST_DEVICE 82 | virtual 83 | rti::vertex_t 84 | operator()(void) 85 | { 86 | std::array phsp = (*fluence)() ; 87 | 88 | rti::vec3 pos(phsp[0], phsp[1], phsp[2]); 89 | rti::vec3 dir(phsp[3], phsp[4], phsp[5]); 90 | 91 | rti::vertex_t vtx; 92 | vtx.ke = (*energy)()[0]; 93 | vtx.pos = p_coord.rotation*pos+p_coord.translation; 94 | vtx.dir = p_coord.rotation*dir; 95 | return vtx; 96 | 97 | }; 98 | }; 99 | 100 | } 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /rti/base/distributions/rti_phsp6d.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_PHSP6D_H 2 | #define RTI_PHSP6D_H 3 | 4 | /// \file 5 | /// 6 | /// Distribution functions (meta-header file for all distributions) 7 | 8 | #include 9 | 10 | namespace rti{ 11 | /// \class phsp_6d 12 | /// 13 | /// 6-dimensional uniform pdf for phase-space variables for a spot 14 | // phase-space variables are position (x,y,z) and direction (x',y',z') 15 | /// \tparam T type of return value 16 | template 17 | class phsp_6d : public pdf_Md { 18 | 19 | /// correlations for x-x' and y-y' respectively 20 | std::array rho_; ///< For X,Y 21 | 22 | public: 23 | 24 | /// Random engine and distribution function 25 | std::default_random_engine gen_ ; 26 | std::normal_distribution func_; 27 | 28 | /// Constructor to initializes mean, sigma, rho, and random engine 29 | /// \param m[0,1,2]: mean spot-position of x, y, z 30 | /// \param m[3,4,5]: mean spot-direction of x', y', z'. 31 | /// \param s[0,1,2]: std spot-position of x,y,z -> spot-size 32 | /// \param s[3,4,5]: std spot-direction of x,y,z. s[5] is ignored but calculated internally 33 | /// \param r[0] : x, xp correlation 34 | /// \param r[1] : y, yp correlation 35 | /// \note seed setup needs to be done by public method 36 | /// gen_.seed(from outside, topas or UI); //Ideally set from TOPAS? 37 | CUDA_HOST_DEVICE 38 | phsp_6d( 39 | std::array& m_, 40 | std::array& s_, 41 | std::array& r_) 42 | : pdf_Md(m_,s_), rho_(r_) 43 | { 44 | #if !defined(__CUDACC__) 45 | gen_.seed(std::chrono::system_clock::now().time_since_epoch().count()); 46 | func_ = std::normal_distribution(0, 1); 47 | #endif 48 | } 49 | 50 | /// Constructor to initializes mean, sigma, rho, and random engine 51 | CUDA_HOST_DEVICE 52 | phsp_6d( 53 | const std::array& m_, 54 | const std::array& s_, 55 | const std::array& r_) 56 | : pdf_Md(m_,s_), rho_(r_) 57 | { 58 | #if !defined(__CUDACC__) 59 | gen_.seed(std::chrono::system_clock::now().time_since_epoch().count()); 60 | func_ = std::normal_distribution(0, 1); 61 | #endif 62 | } 63 | 64 | /// Sample 6 phase-space variables and returns 65 | CUDA_HOST_DEVICE 66 | virtual 67 | std::array 68 | operator()(void) 69 | { 70 | std::array phsp = pdf_Md::mean_; 71 | T Ux = func_(gen_); T Vx = func_(gen_); 72 | T Uy = func_(gen_); T Vy = func_(gen_); 73 | T Uz = func_(gen_); //T Vz = func_(gen_); 74 | phsp[0] += pdf_Md::sigma_[0]* Ux ; 75 | phsp[1] += pdf_Md::sigma_[1]* Uy ; 76 | phsp[2] += pdf_Md::sigma_[2]* Uz ; 77 | 78 | phsp[3] += pdf_Md::sigma_[3] * (rho_[0] * Ux + Vx * std::sqrt(1.0-rho_[0]*rho_[0])); 79 | phsp[4] += pdf_Md::sigma_[4] * (rho_[1] * Uy + Vy * std::sqrt(1.0-rho_[1]*rho_[1])); 80 | phsp[5] = -1.0*std::sqrt( 1.0 - phsp[3]*phsp[3]- phsp[4]*phsp[4] ); 81 | 82 | return phsp; 83 | }; 84 | 85 | }; 86 | 87 | } 88 | #endif 89 | -------------------------------------------------------------------------------- /rti/topas/rtion/TsRTIonComponents.hh: -------------------------------------------------------------------------------- 1 | // 2 | // ******************************************************************** 3 | // * * 4 | // * This code implementation is the intellectual property of the * 5 | // * TOPAS collaboration. * 6 | // * Use or redistribution of this code is not permitted without the * 7 | // * explicit approval of the TOPAS collaboration. * 8 | // * Contact: Joseph Perl, perl@slac.stanford.edu * 9 | // * * 10 | // ******************************************************************** 11 | // author: Jungwook Shin @ mgh (jshin13@mgh.harvard.edu) 12 | 13 | #ifndef TSRTION_COMPONENT_HH 14 | #define TSRTION_COMPONENT_HH 15 | 16 | /// \file 17 | /// 18 | /// TOPAS geometry extiontion for RT-Ion component 19 | 20 | 21 | #include 22 | #include 23 | 24 | #include "TsVGeometryComponent.hh" 25 | 26 | /// \class TsRTIonComponents 27 | class TsRTIonComponents : public TsVGeometryComponent 28 | { 29 | protected: 30 | 31 | std::unique_ptr> rti_session_ {nullptr} ; 32 | 33 | rti::beamline beamline_; 34 | 35 | ///< Get corrdinate system first 36 | rti::coordinate_transform rt_coordinate_dicom_; 37 | rti::coordinate_transform rt_coordinate_topas_; 38 | 39 | ///< Local origin w.r.t World origin 40 | const G4ThreeVector* pos_global_ ; 41 | 42 | ///< shared by all components 43 | const G4RotationMatrix* rot_local_ ; 44 | const G4RotationMatrix* rot_global_ ; 45 | const G4RotationMatrix* rot_posture_ ; 46 | 47 | G4ThreeVector* 48 | ConvertRTIPosition2TOPASPosition( 49 | const rti::vec3& p 50 | ); 51 | 52 | void 53 | ExportDICOMCoordinateToParameters( 54 | rti::coordinate_transform& p 55 | ); 56 | 57 | void ExportDoseGridToParameters( 58 | rti::rect3d& dg, 59 | rti::vec3& ct_p, 60 | rti::vec3& trans_p); 61 | 62 | void 63 | Wrap3Vector( 64 | rti::vec3 vec, 65 | const char* name, 66 | const char* unit=" mm" 67 | ); 68 | 69 | void 70 | Wrap1Vector( 71 | float value, 72 | const char* name, 73 | const char* unit=" deg" 74 | ); 75 | 76 | void 77 | Wrap3IntVector( 78 | rti::vec3 vec, 79 | const char* name 80 | ); 81 | 82 | 83 | bool 84 | ConstructRangeShifter(rti::rangeshifter* rs); 85 | 86 | bool 87 | ConstructBlock(rti::aperture* apt); 88 | 89 | 90 | 91 | public: 92 | TsRTIonComponents( 93 | TsParameterManager* pM, 94 | TsExtensionManager* eM, 95 | TsMaterialManager* mM, 96 | TsGeometryManager* gM, 97 | TsVGeometryComponent* parentComponent, 98 | G4VPhysicalVolume* parentVolume, 99 | G4String& name); 100 | ~TsRTIonComponents(); 101 | 102 | G4VPhysicalVolume* Construct(); 103 | 104 | /* 105 | bool 106 | ConstructDoseGrid( 107 | //std::shared_ptr dg 108 | ); 109 | */ 110 | 111 | 112 | }; 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /rti/base/rti_treatment_machine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_TREATMENT_MACHINE_H 2 | #define RTI_TREATMENT_MACHINE_H 3 | 4 | /// \file 5 | /// 6 | /// Abstraction for treatment machine 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace rti{ 14 | 15 | /// \class treatment_machine 16 | /// 17 | /// Describes an abstraction of all types (RT and ION) treatment machine 18 | /// Typically it consists of geometries (beam limiting devices) and sources (particle fluence) 19 | /// This class has three user-implemented methods, create_beamline, create_beamsource, and create_coordinate_transform 20 | /// \tparam T type of phase-space variables, e.g., float or double 21 | /// \note treatment machine is distinguished in its name 22 | template 23 | class treatment_machine { 24 | protected: 25 | 26 | ///< Machine name in string (site:system:mc_code) 27 | const std::string name_ ; 28 | 29 | ///< Source to Axis distance, 30 | ///< neccessary to calculate beam divergence 31 | std::array SAD_ ; 32 | 33 | ///< Distance from phase-space plan to isocenter 34 | float source_to_isocenter_mm_ ; 35 | 36 | public: 37 | 38 | /// Default constructor 39 | treatment_machine(){;} 40 | 41 | /* 42 | /// Default constructor to set infinite SAD 43 | /// \note not sure yet to include. 44 | treatment_machine(): 45 | SAD_{std::numeric_limits::infinity(), std::numeric_limits::infinity()} 46 | {;} 47 | */ 48 | 49 | /// Virtual destructor of abstract class 50 | virtual ~treatment_machine(){;} 51 | 52 | /// Returns beamline model 53 | /// \param ds : pointer of dataset 54 | /// \param m : modality type such as RTIP, US, PASSIVE, etc 55 | /// \return beamline 56 | virtual 57 | rti::beamline 58 | create_beamline( 59 | const rti::dataset* ds, 60 | rti::modality_type m 61 | ) = 0 ; 62 | 63 | 64 | 65 | /// Returns beamsource model 66 | /// \param ds : pointer of dataset 67 | /// \param m : modality type such as IMPT, US, PASSIVE, etc 68 | /// \param pcoord: coordinate system of beam geometry including gantry, patient support, etc 69 | /// \param scalefactor : total number of histories can be calculated using this number 70 | virtual 71 | rti::beamsource 72 | create_beamsource( 73 | const rti::dataset* ds, 74 | const rti::modality_type m, 75 | const rti::coordinate_transform pcoord, 76 | const float scalefactor = -1, 77 | const float source_to_isocenter_mm = 390.0 78 | ) = 0 ; 79 | 80 | 81 | /// Returns coordinate transform information 82 | /// \param ds : pointer of dataset 83 | /// \param m : modality type such as IMPT, US, PASSIVE, etc 84 | /// \return pcoord: coordinate system of beam geometry including gantry, patient support, etc 85 | virtual 86 | rti::coordinate_transform 87 | create_coordinate_transform( 88 | const rti::dataset* ds, 89 | const rti::modality_type m 90 | ) = 0 ; 91 | 92 | 93 | }; 94 | 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /rti/topas/tutorial/plan.txt: -------------------------------------------------------------------------------- 1 | includeFile = beam.txt 2 | 3 | #################################################### 4 | ##------ Overriding parameters ----- 5 | #################################################### 6 | 7 | Ge/World/HLX = 60.0 cm 8 | Ge/World/HLY = 80.0 cm 9 | Ge/World/HLZ = 60.0 cm 10 | Ge/World/Material = "Air" 11 | 12 | #################################################### 13 | ##------ RTION as layered mass geometry ----- 14 | #################################################### 15 | sv:Ph/Default/LayeredMassGeometryWorlds = 1 "RTION" 16 | 17 | #################################################### 18 | #----------------- RTIonComponent ------------------ 19 | #################################################### 20 | # RTION geometry is parallel 21 | Ge/RTION/IsParallel = "T" 22 | 23 | # --- 24 | # 1. Patient CT to calculate 25 | # Image center in Patient DICOM coordinate system 26 | # Iso center in Patient DICOM coordinate 27 | # As TOPAS places center of patient CT at the origin, 28 | # --- 29 | s:Ge/RTION/ImgDirectory = Rt/RTION/CTDirectory 30 | dc:Ge/RTION/ImgCenterX = 0 mm 31 | dc:Ge/RTION/ImgCenterY = 0 mm 32 | dc:Ge/RTION/ImgCenterZ = 0 mm 33 | 34 | # --- 35 | # 2. Position RTIon components (only beamline component) 36 | # this will not affect dose-grid 37 | # --- 38 | 39 | Ge/RTION/TransX = Ge/RTION/IsoCenterX - Ge/RTION/ImgCenterX mm 40 | Ge/RTION/TransY = Ge/RTION/IsoCenterY - Ge/RTION/ImgCenterY mm 41 | Ge/RTION/TransZ = Ge/RTION/IsoCenterZ - Ge/RTION/ImgCenterZ mm 42 | 43 | # --- 44 | # 3. Rotation RTIon components (only beamline components) 45 | # --- 46 | #RotCollimator/Gantry/PatientSupport/IEC2DICOM are RTION specific 47 | Ge/RTION/RotCollimator = Ge/RTION/CollimatorAngle deg 48 | Ge/RTION/RotGantry = Ge/RTION/GantryAngle deg 49 | Ge/RTION/RotPatientSupport = -1.0 * Ge/RTION/PatientSupportAngle deg 50 | Ge/RTION/RotIEC2DICOM = 90 deg 51 | 52 | #################################################### 53 | #----------------- RTIonSource -------------------- 54 | #################################################### 55 | # --- 56 | # 1. Patient CT to calculate 57 | # --- 58 | s:So/RTION/ImgDirectory = Rt/RTION/CTDirectory 59 | dc:So/RTION/ImgCenterX = 0 mm 60 | dc:So/RTION/ImgCenterY = 0 mm 61 | dc:So/RTION/ImgCenterZ = 0 mm 62 | 63 | # --- 64 | # 2. Position RTIon components (only beamline component) 65 | # this will not affect dose-grid 66 | # --- 67 | So/RTION/ShiftX = So/RTION/IsoCenterX - So/RTION/ImgCenterX mm 68 | So/RTION/ShiftY = So/RTION/IsoCenterY - So/RTION/ImgCenterY mm 69 | So/RTION/ShiftZ = So/RTION/IsoCenterZ - So/RTION/ImgCenterZ mm 70 | 71 | So/RTION/RotCollimator = So/RTION/CollimatorAngle deg 72 | So/RTION/RotGantry = So/RTION/GantryAngle deg 73 | So/RTION/RotPatientSupport = -1.0 * So/RTION/PatientSupportAngle deg 74 | So/RTION/RotIEC2DICOM = 90 deg 75 | 76 | #################################################### 77 | ##------ DICOM Patient ----- 78 | #################################################### 79 | 80 | s:Ge/Patient/Type = "TsDicomPatient" 81 | s:Ge/Patient/Parent = "IEC_F" 82 | s:Ge/Patient/Material = "G4_WATER" 83 | s:Ge/Patient/DicomDirectory = Rt/RTION/CTDirectory 84 | s:Ge/Patient/CloneRTDoseGridFrom = Rt/RTION/DoseFile 85 | d:Ge/Patient/TransX = 0.0 mm 86 | d:Ge/Patient/TransY = -200.0 mm 87 | d:Ge/Patient/TransZ = 0.0 mm 88 | 89 | d:Ge/Patient/RotX = 0. deg 90 | d:Ge/Patient/RotY = 90. deg 91 | d:Ge/Patient/RotZ = 0. deg 92 | # Specify which slices to show. 93 | # Comment this out or set to zero to show all slices. 94 | # Set to -1 to show only center slice. 95 | # Set to -2 to show first, center and last slice. 96 | #iv:Ge/Patient/ShowSpecificSlicesX = 1 -1 97 | #iv:Ge/Patient/ShowSpecificSlicesY = 1 -1 98 | iv:Ge/Patient/ShowSpecificSlicesZ = 1 -1 99 | b:Ge/Patient/IgnoreInconsistentFrameOfReferenceUID = "True" 100 | -------------------------------------------------------------------------------- /rti/base/distributions/rti_phsp6d_fanbeam.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RTI_PHSP_6D_FANBEAM_H 3 | #define RTI_PHSP_6D_FANBEAM_H 4 | 5 | /// \file 6 | /// 7 | /// Distribution functions (meta-header file for all distributions) 8 | 9 | #include 10 | 11 | namespace rti{ 12 | 13 | /// \class phsp_6d_fanbeam 14 | /// 15 | /// 6-dimensional uniform pdf for phase-space variables for a fanbeam (wide) 16 | // phase-space variables are position (x,y,z) and direction (x',y',z') between x_max, x_min and y_max and y_min, etc. 17 | /// \tparam T type of return value 18 | template 19 | class phsp_6d_fanbeam : public pdf_Md { 20 | 21 | /// correlations for x-x' and y-y' respectively 22 | std::array rho_; 23 | /// Source to Axis Distance for x and y. 24 | std::array SAD_; 25 | 26 | public: 27 | 28 | /// Random engine and distribution function 29 | std::default_random_engine gen_ ; 30 | std::normal_distribution func_; 31 | 32 | /// uniform distributions to place x and y position 33 | /// positions are determined with SAD 34 | std::uniform_real_distribution unifx_; 35 | std::uniform_real_distribution unify_; 36 | 37 | /// Constructor to initialize distribution parameters 38 | CUDA_HOST_DEVICE 39 | phsp_6d_fanbeam( 40 | std::array& m_, ///< [x_min, x_max, y_min, y_max, z_min, z_max] 41 | std::array& s_, ///< [sig_x, sig_y, sig_z, sig_x', sig_y', sig_z'] 42 | std::array& r_, ///< rho_ correlation of x,x' and y,y' 43 | std::array& o_ ///< [SADx, SADy] 44 | ) : pdf_Md(m_,s_), 45 | rho_(r_), 46 | SAD_(o_) 47 | { 48 | #if !defined(__CUDACC__) 49 | gen_.seed(std::chrono::system_clock::now().time_since_epoch().count()); 50 | unifx_ = std::uniform_real_distribution(m_[0], m_[1]); 51 | unify_ = std::uniform_real_distribution(m_[2], m_[3]); 52 | func_ = std::normal_distribution(0, 1); 53 | #endif 54 | } 55 | 56 | /// Constructor to initialize distribution parameters 57 | CUDA_HOST_DEVICE 58 | phsp_6d_fanbeam( 59 | const std::array& m_, ///< [x_min, x_max, y_min, y_max, z_min, z_max] 60 | const std::array& s_, ///< [sig_x, sig_y, sig_z, sig_x', sig_y', sig_z'] 61 | const std::array& r_, ///< rho_ correlation of x,x' and y,y' 62 | const std::array& o_ ///< [SADx, SADy] 63 | ) : pdf_Md(m_,s_), 64 | rho_(r_), 65 | SAD_(o_) 66 | { 67 | #if !defined(__CUDACC__) 68 | gen_.seed(std::chrono::system_clock::now().time_since_epoch().count()); 69 | unifx_ = std::uniform_real_distribution(m_[0], m_[1]); 70 | unify_ = std::uniform_real_distribution(m_[2], m_[3]); 71 | func_ = std::normal_distribution(0, 1); 72 | #endif 73 | } 74 | 75 | /// Constructor to initialize distribution parameters 76 | /// phase-space variables are sampled same in phsp_6d but they are spread along x and y. 77 | CUDA_HOST_DEVICE 78 | virtual 79 | std::array 80 | operator()(void) 81 | { 82 | auto x = unifx_(gen_) ; 83 | auto y = unify_(gen_) ; 84 | 85 | rti::vec3 dir(std::atan(x/SAD_[0]), std::atan(y/SAD_[1]), -1.0); 86 | 87 | std::array phsp ; 88 | T Ux = func_(gen_); T Vx = func_(gen_); 89 | T Uy = func_(gen_); T Vy = func_(gen_); 90 | 91 | phsp[0] = x + pdf_Md::sigma_[0]* Ux ; 92 | phsp[1] = y + pdf_Md::sigma_[1]* Uy ; 93 | phsp[2] = pdf_Md::mean_[5] ; 94 | 95 | phsp[3] = dir.x + pdf_Md::sigma_[3] * (rho_[0] * Ux + Vx * std::sqrt(1.0-rho_[0]*rho_[0])); 96 | phsp[4] = dir.y + pdf_Md::sigma_[4] * (rho_[1] * Uy + Vy * std::sqrt(1.0-rho_[1]*rho_[1])); 97 | phsp[5] = -1.0*std::sqrt( 1.0 - phsp[3]*phsp[3]- phsp[4]*phsp[4] ); 98 | 99 | return phsp; 100 | }; 101 | 102 | }; 103 | 104 | 105 | 106 | } 107 | 108 | #endif 109 | 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DICOM RT-Ion interface for MC simulation 2 | *** 3 | 4 | 9 | 10 | > *Current version is BETA as of Aug14, 2019* 11 | 12 | DICOM RT-Ion interface, shortly **RTI**, is a library to convert treatment planning information in DICOM format into Monte Carlo components on-the-fly such as geometries and beam source. The **RTI** allows integration of DICOM-RT Ion interface within a MC engine to provide more reliable and consistent performance than with a script-based processing to interpret DICOM information. 13 | For the Monte Carlo simulation, [TOPAS extensions](https://topas.readthedocs.io/en/latest/extension-docs/intro.html#) of geometry and particle source to connect **RTI** are provided. 14 | 15 | DICOM-RT objects utilized in this interface are 16 | - Ion Plan (**RTIP**) 17 | - Ion Beams Treatment Record (**RTIBTR**) 18 | - CT image 19 | - RT-Dose 20 | > note: RT Plan is not supported (2019. July 22). 21 | 22 | Beamline geometries, gantry and patient coordinate systems, and fluence map are determined from RTIP and/or RTIBTR. CT image and Dose are used only for patient dose calculations. 23 | 24 | ## Getting started 25 | 26 | ### Requirements 27 | 28 | - **[GDCM](http://gdcm.sourceforge.net)** tested versions are 2.4, 2.6.8, and 3.0. 29 | 30 | (GDCM version 3.0 works with RTI if you compile TOPAS 3.9 from source instead of using the binary package.) 31 | 32 | ### Monte Carlo 33 | 34 | - **[TOPAS](http://www.topasmc.org)** are tested for versions 3.1, 3.2, 3.5, 3.7, and 3.9 35 | 36 | ### Tested operating systems 37 | - Mac OS X 38 | - 10.14.5, clang++ (LLVM version 10.0.1, /usr/bin/c++) 39 | - 12.6.2, clang++ (LLVM version 14.0.0, /usr/bin/c++) with topas 3.9 40 | - cmake version 3.24 41 | - Linux 42 | - Red Hat Enterprise Linux Server release 6.7 g++ (4.9.0) 43 | - Ubuntu 12.0 with gcc 11 44 | - Ubuntu 19.10 45 | - Ubuntu 22.04 (gcc 11.3) 46 | 47 | ### Installation 48 | 49 | As **RTI** is a header only library, copy or download the files to somewhere in your system. 50 | ```bash 51 | $ cd // 52 | $ git clone https://github.com/topasmc/dicom-interface rti.git 53 | ``` 54 | 55 | If you are compiling dicom-interface with topas releases ( not from source), you need to use same headers of gdcm that topas used. 56 | ```bash 57 | $ cd //rti.git 58 | $ tar -zxf gdcm-2.6.include.tar.gz 59 | $ ls gdcm-2.6 60 | ``` 61 | 62 | Then, go to the directory where your topas is installed. 63 | 64 | ```bash 65 | $ cd // 66 | ``` 67 | 68 | Add two lines in CMakeList.txt (in TOPAS) as following: 69 | ```cmake 70 | include_directories ( 71 | ${CMAKE_BINARY_DIR} 72 | ${CMAKE_BINARY_DIR}/extensions 73 | ${PROJECT_SOURCE_DIR}/Geant4Headers 74 | ${PROJECT_SOURCE_DIR}/include 75 | //rti.git/ 76 | //rti.git/gdcm-2.6 77 | ) 78 | ``` 79 | 80 | 81 | ```bash 82 | $ cmake -DTOPAS_EXTENSIONS_DIR=//rti.git/rti/topas/rtion . 83 | $ make -j4 84 | ``` 85 | 86 | ### Run a test 87 | 88 | ```bash 89 | $ cd /your_sw_path/rti.git/topas/tutorial/ 90 | $ topas beam_view.txt 91 | ``` 92 | 93 | For more detail, please see this project's wiki page [https://github.com/topasmc/dicom-interface/wiki](https://github.com/topasmc/dicom-interface/wiki). 94 | 95 | ## Authors 96 | 97 | - **Shin, Jungwook**: main developments and documentations. 98 | - **Hueso-Gonzalez, Fernando**: documentations and discussion 99 | - **Edmunds, David**: GPU (cuda) implementation 100 | - **Kooy, Hanne, M.** : Advisor 101 | - **Paganetti, Harald** : Advisor 102 | - **Clasie, Benjamin M.** : Advisor 103 | 104 | ## Acknowledgements 105 | 106 | This project is initiated by Massachusetts General Hospital and continuously supported by a NIH grant, TOPAS project (U24). 107 | 108 | ## How to cite 109 | 110 | Please cite this paper: https://doi.org/10.1016/j.ejmp.2020.04.018 111 | 112 | ## License (TBD): 113 | 114 | This project is licensed under - see the LICENSE.md file for details. 115 | -------------------------------------------------------------------------------- /rti/base/rti_rect2d.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_RECT2D_H 2 | #define RTI_RECT2D_H 3 | 4 | /// \file 5 | /// 6 | /// 2D rectangle grid 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined(__CUDACC__) 16 | #include 17 | #include 18 | #include 19 | //#include "helper/helper_cuda.h" 20 | //#include "helper/helper_math.h" 21 | #include 22 | #include 23 | #endif 24 | 25 | #include 26 | #include 27 | 28 | namespace rti{ 29 | 30 | /// \class rect2d 31 | /// \tparam T for grid coordinate (float or double) a type of x, y, and z positions 32 | template 33 | class rect2d { 34 | 35 | public: 36 | /// Enumerate 37 | /// Following lines can be accessible as 38 | /// rti::rect2d mycell(...); 39 | /// mycell[XP]; will return const l11to10 40 | /// mycell[XP].p1 ; will return first point 41 | /// mycell[XP].p2 ; will return first point 42 | typedef enum 43 | { //corner a,b,c,d 44 | XP=0, ///< X plus 45 | YP=1, ///< Y plus 46 | XM=2, ///< X minus 47 | YM=3, ///< Y minus 48 | NOSIDE=4 49 | } cell_side; 50 | 51 | rti::line2d l00to01 ; ///< xminus 52 | rti::line2d l01to11 ; ///< yplus 53 | rti::line2d l11to10 ; ///< xplus 54 | rti::line2d l10to00 ; ///< yminus 55 | 56 | rti::vec2 center ; 57 | rti::vec2 dxy ; 58 | rti::vec2 d05_xy ; 59 | 60 | CUDA_HOST_DEVICE 61 | rect2d( 62 | rti::vec2 c, 63 | rti::vec2 d) 64 | : center(c) , 65 | dxy(d), 66 | d05_xy(d*0.5) 67 | { 68 | update_lines(); 69 | } 70 | 71 | CUDA_HOST_DEVICE 72 | rect2d(const rect2d& ref ) 73 | : l00to01(ref.l00to01), 74 | l01to11(ref.l01to11), 75 | l11to10(ref.l11to10), 76 | l10to00(ref.l10to00), 77 | center(ref.center), 78 | dxy(ref.dxy), 79 | d05_xy(ref.d05_xy) 80 | {;} 81 | 82 | CUDA_HOST_DEVICE 83 | ~rect2d(){;} 84 | 85 | CUDA_HOST_DEVICE 86 | void 87 | change_position( rti::vec2& c ) 88 | { 89 | center = c; 90 | update_lines(); 91 | } 92 | 93 | CUDA_HOST_DEVICE 94 | void 95 | change_size( rti::vec2& d ) 96 | { 97 | dxy = d; 98 | update_lines(); 99 | } 100 | 101 | CUDA_HOST_DEVICE 102 | void 103 | update_lines( void ) 104 | { 105 | 106 | l00to01.p1.x = center.x - d05_xy.x; l00to01.p1.y = center.y - d05_xy.y; 107 | l00to01.p2.x = center.x - d05_xy.x; l00to01.p2.y = center.y + d05_xy.y; 108 | 109 | l01to11.p1.x = center.x - d05_xy.x; l01to11.p1.y = center.y + d05_xy.y; 110 | l01to11.p2.x = center.x + d05_xy.x; l01to11.p2.y = center.y + d05_xy.y; 111 | 112 | l11to10.p1.x = center.x + d05_xy.x; l11to10.p1.y = center.y + d05_xy.y; 113 | l11to10.p2.x = center.x + d05_xy.x; l11to10.p2.y = center.y - d05_xy.y; 114 | 115 | l10to00.p1.x = center.x + d05_xy.x; l10to00.p1.y = center.y - d05_xy.y; 116 | l10to00.p2.x = center.x - d05_xy.x; l10to00.p2.y = center.y - d05_xy.y; 117 | 118 | } 119 | 120 | 121 | CUDA_HOST_DEVICE 122 | T 123 | intersect_alpha( 124 | rti::line2d& line, 125 | cell_side which_side) const 126 | { 127 | return (*this)[which_side].intersect_alpha(line); 128 | } 129 | 130 | CUDA_HOST_DEVICE 131 | std::array 132 | intersect_alpha( 133 | rti::line2d& line) 134 | const 135 | { 136 | std::array v; 137 | v[XP] = this->intersect_alpha(line, XP); 138 | v[XM] = this->intersect_alpha(line, XM); 139 | v[YP] = this->intersect_alpha(line, YP); 140 | v[YM] = this->intersect_alpha(line, YM); 141 | return v; 142 | } 143 | 144 | CUDA_HOST_DEVICE 145 | const rti::line2d& 146 | operator[](cell_side which_side) 147 | const 148 | { 149 | //check which_side > NOSIDE 150 | switch( which_side ){ 151 | case XM: 152 | return l00to01; 153 | case XP: 154 | return l11to10; 155 | case YM: 156 | return l10to00; 157 | case YP: 158 | return l01to11; 159 | default: 160 | throw; //should be an error 161 | } 162 | } 163 | 164 | }; 165 | 166 | } 167 | 168 | #endif -------------------------------------------------------------------------------- /rti/base/rti_coordinate_transform.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_COORDINATE_TRANSFORM_HPP 2 | #define RTI_COORDINATE_TRANSFORM_HPP 3 | 4 | /// \file 5 | /// 6 | /// A coordinate transform to map a history from beamsource to map a IEC coordinate or DICOM coordinate. 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | 19 | namespace rti{ 20 | 21 | /// \class coordinate_transform 22 | /// default units are mm for length and degree for angle. 23 | /// rotation direction is CCW 24 | /// order of rotation is collimator->gantry->couch->iec2dicom 25 | /// \tparam T for types for return values by the distributions 26 | template 27 | class coordinate_transform{ 28 | public: 29 | 30 | /// A constant to convert degree to radian. 31 | const float deg2rad = M_PI/180.0; 32 | 33 | /// Final rotation matrix and translation vector 34 | rti::mat3x3 rotation ; 35 | rti::vec3 translation ; 36 | 37 | /// rotation matrices 38 | rti::mat3x3 collimator ; ///< Rotation due to collimator angle 39 | rti::mat3x3 gantry ; ///< Rotation due to gantry angle 40 | rti::mat3x3 patient_support ; ///< Rotation due to couch 41 | rti::mat3x3 iec2dicom ; ///-90 deg (iec2dicom), 90 deg (dicom2iec) 42 | 43 | 44 | /// Constructor with 4-angles and position 45 | /// \param angles[4] angles of collimator, gantry, couch, and iec 46 | /// \param pos move origin, i.e, isocenter 47 | CUDA_HOST_DEVICE 48 | coordinate_transform( 49 | std::array& angles, 50 | rti::vec3& pos) 51 | : translation(pos) 52 | { 53 | collimator = rti::mat3x3(0, 0, angles[0]); 54 | gantry = rti::mat3x3(0, angles[1], 0); 55 | patient_support = rti::mat3x3(0, 0, angles[2]); 56 | iec2dicom = rti::mat3x3(angles[3], 0, 0); 57 | rotation = iec2dicom * patient_support * gantry * collimator ; 58 | } 59 | 60 | /// Constructor with constant 4-angles and position 61 | /// \param const angles[4] angles of collimator, gantry, couch, and iec 62 | /// \param const pos 63 | CUDA_HOST_DEVICE 64 | coordinate_transform( 65 | const std::array& angles, 66 | const rti::vec3& pos) 67 | : translation(pos) 68 | { 69 | collimator = rti::mat3x3(0,0, angles[0]); 70 | gantry = rti::mat3x3(0, angles[1], 0); 71 | patient_support = rti::mat3x3(0, 0, angles[2]); 72 | iec2dicom = rti::mat3x3(angles[3], 0, 0); 73 | rotation = iec2dicom * patient_support * gantry * collimator ; 74 | } 75 | 76 | /// A copy constructor 77 | CUDA_HOST_DEVICE 78 | coordinate_transform(const coordinate_transform& ref) 79 | { 80 | collimator = ref.collimator; 81 | gantry = ref.gantry; 82 | patient_support = ref.patient_support; 83 | iec2dicom = ref.iec2dicom; 84 | rotation = iec2dicom * patient_support * gantry * collimator ; 85 | translation = ref.translation; 86 | } 87 | 88 | /// Destructor 89 | CUDA_HOST_DEVICE 90 | coordinate_transform(){;} 91 | 92 | /// Assignment operator 93 | CUDA_HOST_DEVICE 94 | coordinate_transform& 95 | operator=(const coordinate_transform& ref) 96 | { 97 | collimator = ref.collimator; 98 | gantry = ref.gantry; 99 | patient_support = ref.patient_support; 100 | iec2dicom = ref.iec2dicom; 101 | rotation = iec2dicom * patient_support * gantry * collimator ; 102 | translation = ref.translation; 103 | return *this; 104 | } 105 | 106 | /// Prints out matrix 107 | CUDA_HOST 108 | void 109 | dump() 110 | { 111 | std::cout<<"--- coordinate transform---"<< std::endl; 112 | std::cout<<" translation ---"<< std::endl; 113 | translation.dump(); 114 | std::cout<<" rotation ---"<< std::endl; 115 | rotation.dump(); 116 | std::cout<<" gantry ---"<< std::endl; 117 | gantry.dump(); 118 | std::cout<<" patient_support ---"<< std::endl; 119 | patient_support.dump(); 120 | std::cout<<" collimator ---"<< std::endl; 121 | collimator.dump(); 122 | std::cout<<" IEC2DICOM ---"<< std::endl; 123 | iec2dicom.dump(); 124 | } 125 | 126 | }; 127 | 128 | } 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /rti/base/rti_beam_module_ion.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_BEAM_MODULE_ION_H 2 | #define RTI_BEAM_MODULE_ION_H 3 | 4 | /// \file 5 | /// 6 | /// Interprets DICOM-RT Ion beam module 7 | /// \see http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.8.25.html for RTI 8 | /// \see http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.8.26.html for RTIBTR 9 | 10 | #include 11 | 12 | namespace rti { 13 | 14 | /// Scan type from a tag (300A,0308) 15 | typedef enum{ 16 | NONE=0, 17 | UNIFORM=1, 18 | MODULATED=2, 19 | MODULATED_SPEC=3 20 | } SCAN_MODE; 21 | 22 | /// \class beam_module_ion 23 | /// A class for the RTION beams (plan & treatment record) 24 | 25 | class beam_module_ion : public beam_module { 26 | public: 27 | 28 | /// User-defined type for a spot 29 | typedef struct { 30 | float e; ///< The energy in MeV 31 | float x; ///< The x-position in mm 32 | float y; ///< The y-position in mm 33 | float fwhm_x; ///< The full-width-half maximum for x 34 | float fwhm_y; ///< The full-width-hafl maximum for y 35 | float meterset; ///< The meterset weight, e.g.,MU or NP. 36 | } spot ; 37 | 38 | protected: 39 | 40 | /// Number of spots as a function of layer-id 41 | std::vector nb_spots_per_layer_; 42 | 43 | /// All spots in delivery order. 44 | std::vector< spot > sequence_; 45 | 46 | /// Name of beam model 47 | std::string tune_id_ ; 48 | 49 | public: 50 | 51 | /// Constructs beam module for RT-Ion 52 | /// \param d DICOM dataset of either C.8.8.25-1 (plan) or C.8.8.26-1 (record) 53 | /// \param m a modality type, e.g., ION Plan or ION Record 54 | beam_module_ion( 55 | const rti::dataset* d, 56 | rti::modality_type mod) 57 | :beam_module(d,mod) 58 | { 59 | /// Initializes containers 60 | std::vector nb_pts(1) ; 61 | std::vector energy(1) ; 62 | std::vector fwhm_xy(2) ; 63 | std::vector tune_id(1) ; 64 | std::vector xy ; 65 | std::vector weight ; 66 | 67 | int layer_nb = 0 ; 68 | 69 | std::string str_weight ; 70 | 71 | /// Checks modality type 72 | switch(modality_){ 73 | case rti::modality_type::IONPLAN: 74 | str_weight = "ScanSpotMetersetWeights" ; 75 | break; 76 | case rti::modality_type::IONRECORD: 77 | str_weight = "ScanSpotMetersetsDelivered"; 78 | break; 79 | default: 80 | throw std::runtime_error("Wrong ION type"); 81 | } 82 | 83 | /// Fill the containers from the DICOM dataset 84 | /// As each layer consists of pair of ion-controls and even-layers have all zero weights. 85 | /// So we drop even layer. 86 | auto seq_tags = &rti::seqtags_per_modality.at(mod); 87 | auto ictrl = (*ds_)(seq_tags->at("ctrl")); 88 | for(auto b : ictrl){ 89 | 90 | if ( (layer_nb++)%2) continue; 91 | 92 | b->get_values("ScanSpotTuneID", tune_id); 93 | b->get_values("NominalBeamEnergy", energy); 94 | b->get_values("NumberOfScanSpotPositions", nb_pts) ; 95 | b->get_values("ScanningSpotSize", fwhm_xy); 96 | b->get_values("ScanSpotPositionMap", xy); 97 | b->get_values(str_weight.c_str(), weight); 98 | 99 | for(int j = 0 ; j < nb_pts[0] ; ++j){ 100 | tune_id_ = tune_id[0]; 101 | sequence_.push_back({energy[0], xy[j*2], xy[j*2+1], fwhm_xy[0], fwhm_xy[1], weight[j]}); 102 | }//per spot 103 | nb_spots_per_layer_.push_back(nb_pts[0]); 104 | }//per layer 105 | 106 | } 107 | 108 | /// Destructor 109 | ~beam_module_ion(){;} 110 | 111 | /// Returns the vector pointer for number of spots as a function of layer-id 112 | const 113 | std::vector* 114 | get_nb_spots_per_layer(void) const 115 | { 116 | return &nb_spots_per_layer_; 117 | } 118 | 119 | /// Returns a pointer of spot-sequence vector 120 | const 121 | std::vector* 122 | get_sequence(void) const 123 | { 124 | return &sequence_; 125 | } 126 | 127 | /// Returns tune-id 128 | const 129 | std::string 130 | get_tune_id(void) const 131 | { 132 | return tune_id_; 133 | } 134 | 135 | /// Prints out spot-sequence 136 | void 137 | dump() const 138 | { 139 | std::cout<<"dump:spotmap, size:"<< sequence_.size() < 9 | 10 | namespace rti{ 11 | 12 | /// \class beamsource 13 | /// 14 | /// \tparam T for types for return values by the distributions 15 | /// \note 16 | template 17 | class beamsource { 18 | public: 19 | 20 | /// A beamlet container. 21 | /// Each element is a tuple of beamlet, number of histories, and accumlated histories 22 | std::vector, size_t, size_t>> beamlets_; 23 | 24 | /// A lookup table to map a history to beamlet id. 25 | /// note: To run GPU, this std::map needs to be replaced GPU compatible data structure. 26 | std::map cdf2beamlet_; 27 | 28 | /// A lookup table to map a time to beamlet id. 29 | //time, beamlet_id 30 | //beamlet_id is -1 for no beam pulse 31 | std::map timeline_; 32 | 33 | /// Default constructor 34 | beamsource(){ 35 | beamlets_.clear(); 36 | timeline_.clear(); 37 | cdf2beamlet_.clear(); 38 | } 39 | 40 | /// Add a beamlet to internal containers 41 | /// \param b a beamlet 42 | /// \param h number of histories 43 | /// \param p coordinate transformation 44 | void 45 | append_beamlet( 46 | rti::beamlet b, 47 | size_t h, 48 | rti::coordinate_transform p, 49 | T time_on = 1, 50 | T time_off = 0 ) 51 | { 52 | b.set_coordinate_transform(p); 53 | this->append_beamlet(b,h, time_on, time_off); 54 | } 55 | 56 | /// Add a beamlet to internal containers. 57 | /// \param b a beamlet 58 | /// \param h number of histories 59 | void 60 | append_beamlet( 61 | rti::beamlet b, 62 | size_t h, 63 | T time_on = 1, 64 | T time_off = 0) 65 | { 66 | const size_t acc = total_histories() + h ; 67 | const size_t beamlet_id = this->total_beamlets(); //current number of beamlets -> beamlet ID 68 | cdf2beamlet_.insert( std::make_pair(acc, beamlet_id) ); 69 | beamlets_.push_back( std::make_tuple(b,h,acc) ); 70 | 71 | T acc_time = this->total_delivery_time() + time_on ; 72 | timeline_.insert(std::make_pair(acc_time, beamlet_id)); 73 | if (time_off != 0 ){ 74 | acc_time += time_off ; 75 | timeline_.insert(std::make_pair(acc_time, -1)); 76 | } 77 | } 78 | 79 | /// Total delivery time 80 | /// \return end of timeline 81 | T 82 | total_delivery_time() const 83 | { 84 | if(timeline_.size() == 0) return 0.0; 85 | return std::prev(timeline_.end())->first; 86 | } 87 | 88 | /// Returns size of beamlets. 89 | /// \return total number of beamlets 90 | std::size_t 91 | total_beamlets() const 92 | { 93 | return beamlets_.size(); 94 | } 95 | 96 | /// Returns total number of histories 97 | /// \return total number of histories 98 | std::size_t 99 | total_histories() const 100 | { 101 | return this->total_beamlets() == 0 ? 102 | 0 : std::get<2>(beamlets_.back()); 103 | } 104 | 105 | /// Returns a tuple for given beamlet id. 106 | /// \return a tuple of beamlet, histories, and accumulated histories 107 | std::tuple, size_t, size_t>& 108 | operator[] 109 | (unsigned int i) 110 | { 111 | return beamlets_[i]; 112 | } 113 | 114 | /// Returns a beamlet of a history 115 | /// \return a beamlet reference (const) 116 | rti::beamlet& 117 | operator() 118 | (size_t h) const 119 | { 120 | size_t beamlet_id = cdf2beamlet_.upper_bound(h)->second; 121 | return std::get<0>(beamlets_[beamlet_id]); 122 | } 123 | 124 | /// Calculate number of accumulated histories up to given time 125 | /// \return history as size_t 126 | /// \param time 127 | size_t 128 | cumulative_history_at_time 129 | (T t0) 130 | { 131 | auto pulse = timeline_.lower_bound(t0); 132 | if(pulse == timeline_.end()) return this->total_histories(); 133 | 134 | if(pulse->second == -1){ 135 | while(pulse->second ==-1) --pulse; 136 | return std::get<2>(beamlets_[pulse->second]); 137 | } 138 | 139 | size_t history = std::get<2>(beamlets_[pulse->second]); 140 | 141 | T pulse_time[2]; 142 | pulse_time[0] = (pulse == timeline_.begin()) ? 0.0 : std::prev(pulse)->first; 143 | pulse_time[1] = pulse->first; 144 | 145 | const T ratio = (t0 - pulse_time[0])/(pulse_time[1] - pulse_time[0]); 146 | 147 | if ( ratio >= 0){ 148 | const size_t h0 = std::get<1> (beamlets_[pulse->second]); 149 | const size_t h1 = (size_t) std::floor( (1.0-ratio) * h0); 150 | history -= h1 ; 151 | } 152 | return history; 153 | } 154 | }; 155 | 156 | } 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /rti/base/rti_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_UTILS_H 2 | #define RTI_UTILS_H 3 | 4 | 5 | /// \file 6 | /// Header file containing general functions useful for several classes 7 | /// \see http://www.martinbroadhurst.com/how-to-trim-a-stdstring.html 8 | /// \see https://stackoverflow.com/questions/1798112/removing-leading-and-trailing-spaces-from-a-string 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace rti{ 18 | 19 | ///< Remove white-space on right 20 | inline std::string trim_right_copy(const std::string& s,const std::string& delimiters = " \f\n\r\t\v\0\\" ) 21 | { 22 | return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); 23 | } 24 | 25 | ///< Remove white-space on left 26 | inline std::string trim_left_copy(const std::string& s,const std::string& delimiters = " \f\n\r\t\v\0\\" ) 27 | { 28 | return s.substr( s.find_first_not_of( delimiters ) ); 29 | } 30 | 31 | ///< Remove white-space on left and right 32 | inline std::string trim_copy(const std::string& s,const std::string& delimiters = " \f\n\r\t\v\0\\" ) 33 | { 34 | return trim_left_copy( trim_right_copy( s, delimiters ), delimiters ); 35 | } 36 | 37 | /// Interpolates values in map 38 | /// \tparam T is type of values 39 | /// \tparam S is size of columns 40 | /// \param db map of dataset 41 | /// \param x position value where interpolated value is calculated at 42 | /// \param y_col column index of map for y-values to be used for interpolation 43 | template 44 | inline 45 | T interp_linear( 46 | const std::map>& db, 47 | const T x, 48 | const size_t y_col=0) 49 | { 50 | auto it_up = db.upper_bound(x); 51 | if(it_up == db.end()){ 52 | return ((--it_up)->second)[y_col]; 53 | } 54 | if(it_up == db.begin()){ 55 | return (it_up->second)[y_col]; 56 | } 57 | T x1 = it_up->first; 58 | T y1 = (it_up->second)[y_col]; 59 | auto it_down = --it_up; 60 | T x0 = it_down->first; T y0 = (it_down->second)[y_col]; 61 | return y0 + (x-x0)*(y1-y0)/(x1 - x0); 62 | } 63 | 64 | /// Interpolates values in vector 65 | /// \tparam T is type of values 66 | /// \tparam S is size of columns 67 | /// \param db is vector for dataset 68 | /// \param x position value where interpolated value is calculated at 69 | /// \param x_col column index of map for x-values to be used for interpolation 70 | /// \param y_col column index of map for y-values to be used for interpolation 71 | template 72 | inline 73 | T interp_linear( 74 | const std::vector>& db, 75 | const T x, 76 | const size_t x_col =0, 77 | const size_t y_col=1) 78 | { 79 | if( x <= db[0][x_col] ) return db[0][y_col]; 80 | 81 | for(size_t i = 1 ; i < db.size() - 2 ; ++i){ 82 | if( x <= db[i][x_col] ){ 83 | 84 | T x0 = db[i-1][x_col]; 85 | T x1 = db[i][x_col]; 86 | T y0 = db[i-1][y_col]; 87 | T y1 = db[i][y_col]; 88 | 89 | return y0 + (x-x0)*(y1-y0)/(x1 - x0); 90 | 91 | } 92 | } 93 | 94 | return db[db.size()-1][y_col]; 95 | 96 | } 97 | 98 | 99 | 100 | 101 | /// Interpolate table lambda function 102 | /// \param vector_X The array of x coordinates 103 | /// \param vector_Y The array of y coordinates 104 | /// \param x the ordinate to evaluate 105 | /// \param npoints the number of coordinates in the table 106 | /// \return the y value corresponding to the x ordinate 107 | /// \note from gpmc code 108 | inline 109 | float 110 | TableInterpolation( 111 | float* const vector_X, 112 | float* const vector_Y, 113 | const float x, 114 | const int npoints) 115 | { 116 | float result; 117 | int order = 4; // order of the poly 118 | // Allocate enough space for any table we'd like to read. 119 | // check order of interpolation 120 | if (order > npoints) order = npoints; 121 | // if x is ouside the vector_X[] interval 122 | if (x <= vector_X[0]) return result = vector_Y[0]; 123 | if (x >= vector_X[npoints-1]) return result = vector_Y[npoints-1]; 124 | // loop to find j so that x[j-1] < x < x[j] 125 | int j=0; 126 | while (j < npoints) 127 | { 128 | if (vector_X[j] >= x) break; 129 | j++; 130 | } 131 | // shift j to correspond to (npoint-1)th interpolation 132 | j = j - order/2; 133 | // if j is ouside of the range [0, ... npoints-1] 134 | if (j < 0) j=0; 135 | if (j+order > npoints ) j=npoints-order; 136 | result = 0.0; 137 | float* lambda = new float[npoints]; 138 | for (int is = j; is < j+order; is++) 139 | { 140 | lambda[is] = 1.0; 141 | for (int il=j; il < j+order; il++) 142 | { 143 | if(il != is) lambda[is] = lambda[is]*(x-vector_X[il])/(vector_X[is]-vector_X[il]); 144 | } 145 | result += vector_Y[is]*lambda[is]; 146 | } 147 | delete[] lambda; 148 | return result; 149 | } 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /rti/base/rti_track.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_TRACK_HPP 2 | #define RTI_TRACK_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rti{ 8 | 9 | ///< Particle type 10 | typedef 11 | enum{ 12 | PHOTON = 0, 13 | ELECTRON = 1, 14 | PROTON = 2, 15 | NEUTRON = 3 16 | } particle_t; 17 | //PDG[PHOTON] = 18 | //PDG[PROTON] = 2212 // 19 | 20 | ///< Process type 21 | typedef 22 | enum{ 23 | BEGIN , 24 | MAX_STEP , 25 | BOUNDARY , 26 | CSDA , 27 | D_ION , 28 | PP_E , 29 | PO_E , 30 | PO_I 31 | } process_t; 32 | ///< status of particle 33 | ///< CREATED : just created 34 | ///< ALIVE : under tracking 35 | ///< STOPPED : no further tracking is required due to limitation, e.g., cut 36 | ///< KILLED : no further tracking is required due to energy 0 or exit world boundary? 37 | typedef 38 | enum{ 39 | CREATED = 0, ///< created 40 | // PRE_STEP = 1, ///< tracking. next vertex is calculated 41 | //POST_STEP = 2, 42 | STOPPED = 3 ///< stopped by physics process 43 | } status_t; 44 | 45 | 46 | ///< Track class 47 | /// pointer to geometry where current track is placed 48 | /// pre-/post- vertex points: vtx0 vtx1 49 | 50 | template 51 | class track_t { 52 | public: 53 | status_t status ; ///< particle status 54 | process_t process ; ///< id of physics process that limit the step, 55 | ///< -1: geometry, 0: CSDA, 1: delta, 2: pp-e, 3: po-e, 4: po-i 56 | bool primary ; 57 | particle_t particle ; ///< particle type, 58 | 59 | vertex_t vtx0 ; ///< vertex pre 60 | vertex_t vtx1 ; ///< vertex post 61 | 62 | R dE ; ///< total energy deposit between vtx0 to vtx1 63 | 64 | node_t* c_node = nullptr ; //current node 65 | 66 | ///< auxiliary information for current node 67 | uint32_t cnb =0 ; ///copy number of geometry of a node, 0 is default 68 | vec3 cell ; 69 | cell_side side = rti::NONE_XYZ_PLANE ; 70 | 71 | ///< Defaut constructor 72 | CUDA_HOST_DEVICE 73 | track_t() : status(CREATED), process(BEGIN), primary(true), dE(0) 74 | {;} 75 | 76 | ///< Constructor 77 | CUDA_HOST_DEVICE 78 | track_t(const vertex_t& v) : status(CREATED), process(BEGIN), primary(true), dE(0) 79 | { vtx0 = v; 80 | vtx1 = v;} 81 | 82 | ///< Constructor 83 | CUDA_HOST_DEVICE 84 | track_t 85 | (status_t s, 86 | process_t p, 87 | bool is_p, 88 | particle_t t, 89 | vertex_t v0, 90 | vertex_t v1, 91 | const R& dE) 92 | : status(s), process(p), primary(is_p), 93 | particle(t), vtx0(v0), vtx1(v1), dE(0) 94 | {;} 95 | 96 | ///< copy constructor 97 | CUDA_HOST_DEVICE 98 | track_t 99 | (const track_t& rhs) 100 | { 101 | status = rhs.status ; 102 | process = rhs.process ; 103 | particle = rhs.particle ; 104 | primary = rhs.primary ; 105 | vtx0 = rhs.vtx0 ; 106 | vtx1 = rhs.vtx1 ; 107 | dE = rhs.dE ; 108 | c_node = rhs.c_node ; 109 | cnb = rhs.cnb ; 110 | cell = rhs.cell ; 111 | side = rhs.side ; 112 | } 113 | 114 | ///< Destructor 115 | CUDA_HOST_DEVICE 116 | ~track_t() 117 | {;} 118 | 119 | 120 | ///< Deposit energy 121 | CUDA_HOST_DEVICE 122 | void 123 | deposit(R e) 124 | { 125 | dE += e ; 126 | } 127 | 128 | CUDA_HOST_DEVICE 129 | bool 130 | is_stopped() 131 | { return status == STOPPED ;} 132 | 133 | ///< Update vertex point for given R 134 | CUDA_HOST_DEVICE 135 | void 136 | shorten_step 137 | (R ratio) //0 < ratio < 1 138 | { 139 | vtx1.pos = vtx0.pos + (vtx1.pos - vtx0.pos) * ratio ; 140 | } 141 | 142 | 143 | ///< 144 | CUDA_HOST_DEVICE 145 | void 146 | update_post_vertex_direction 147 | (const R& theta, 148 | const R& phi, 149 | const vec3& dir_z = vec3(0,0,-1)) 150 | { 151 | 152 | rti::mat3x3 m_local(0, theta, phi); 153 | rti::vec3 d_local = m_local * dir_z ; d_local.normalize(); 154 | rti::mat3x3 m_global(dir_z, vtx1.dir); 155 | vtx1.dir = m_global * d_local ; 156 | vtx1.dir.normalize(); 157 | } 158 | 159 | ///< called by CSDA. 160 | ///< no needs to get called by nuclear interactions 161 | CUDA_HOST_DEVICE 162 | void 163 | update_post_vertex_position 164 | (const R& len) 165 | { 166 | vtx1.pos = vtx0.pos + vtx0.dir * len ; 167 | } 168 | 169 | ///< 170 | CUDA_HOST_DEVICE 171 | void 172 | update_post_vertex_energy 173 | (const R& e) 174 | { 175 | vtx1.ke -= e; 176 | } 177 | 178 | ///< Proceed a step 179 | ///< vtx0 = vtx1 180 | CUDA_HOST_DEVICE 181 | void 182 | move() 183 | { 184 | vtx0 = vtx1 ; 185 | dE = 0 ; 186 | } 187 | 188 | ///< Change particle status 189 | CUDA_HOST_DEVICE 190 | void 191 | stop() 192 | { 193 | //this->move(); //don't put move here 194 | status = STOPPED; 195 | } 196 | 197 | ///< Prints out track values CPU only as std libary is used 198 | /* 199 | CUDA_HOST 200 | void 201 | dump(){ 202 | std::cout 203 | << "Trak ID: " << id 204 | << ", Particle: " << particle 205 | << ", Status: " << status 206 | << ", Vertex (Energy, pos, dir): " 207 | << vtx0.ke <<", (" 208 | << vtx0.pos.x <<", " << vtx0.pos.y <<", "<< vtx0.pos.z <<") ," 209 | << vtx0.dir.x <<", " << vtx0.dir.y <<", "<< vtx0.dir.z 210 | <<") to " 211 | << vtx1.ke <<", (" 212 | << vtx1.pos.x <<", " << vtx1.pos.y <<", "<< vtx1.pos.z <<") ," 213 | << vtx1.dir.x <<", " << vtx1.dir.y <<", "<< vtx1.dir.z <<") \n"; 214 | } 215 | */ 216 | 217 | }; 218 | 219 | 220 | } 221 | #endif 222 | -------------------------------------------------------------------------------- /rti/topas/tutorial/beam.txt: -------------------------------------------------------------------------------- 1 | ################################################## 2 | #----------------- IncludeFiles ------------------ 3 | # Beam describing chain 4 | # Beam control chain from RT-Ion Plan 5 | # Target describing chain 6 | # Target scoring 7 | ################################################### 8 | 9 | includeFile = inputs.txt 10 | 11 | i:Ts/MaxInterruptedHistories = 1000 12 | 13 | ################################################### 14 | #----------------- World volume ------------------ 15 | ################################################### 16 | Ge/World/HLX = 50.0 cm 17 | Ge/World/HLY = 50.0 cm 18 | Ge/World/HLZ = 50.0 cm 19 | Ge/World/Material = "Air" 20 | 21 | ################################################### 22 | #----------------- Coordination ------------------ 23 | ################################################### 24 | #IEC_F: Fixed : 25 | # Note: Don't rotate this (April4,2019). translation is OK 26 | s:Ge/IEC_F/Parent = "World" 27 | s:Ge/IEC_F/Type = "Group" 28 | d:Ge/IEC_F/RotX = 0. deg 29 | d:Ge/IEC_F/RotY = 0. deg #Geometry and Source rotate oposite 30 | d:Ge/IEC_F/RotZ = 0. deg #? 31 | d:Ge/IEC_F/TransX = 0. mm 32 | d:Ge/IEC_F/TransY = 0. mm 33 | d:Ge/IEC_F/TransZ = 0. mm 34 | 35 | 36 | #################################################### 37 | ### RangeShifter/Aperture/Compensator become a mass 38 | ### geometry for only patient calclation 39 | ##################################################### 40 | #################################################### 41 | ### RangeShifter/Aperture/Compensator become a mass 42 | ### geometry for only patient calclation 43 | ### 1.15 is from Astroid Database (this might be RSP) 44 | ### we are using widely accepted PMMA density 45 | ### 1.180 g/cm3 and 74.0 is used. 46 | 47 | ##################################################### 48 | sv:Ma/RS_Lucite/Components =3 "Hydrogen" "Carbon" "Oxygen" 49 | uv:Ma/RS_Lucite/Fractions =3 0.080538 0.599848 0.319614 50 | d:Ma/RS_Lucite/Density = 1.18 g/cm3 51 | d:Ma/RS_Lucite/MeanExcitationEnergy=74.0 eV 52 | s:Ma/RS_Lucite/DefaultColor="grey" 53 | #3 G4_PLEXIGLASS 1.19 74 54 | # 1 0.080538 55 | # 6 0.599848 56 | # 8 0.319614 57 | 58 | 59 | ################################################### 60 | #-- RTION geometry 61 | ################################################### 62 | # RTION is a group of geometries specified in RTION plan file 63 | # BeamNumber or BeamName can pick the one 64 | 65 | s:Ge/RTION/Parent = "IEC_F" 66 | s:Ge/RTION/Type = "TsRTIonComponents" 67 | s:Ge/RTION/File = Rt/RTION/PlanFile 68 | i:Ge/RTION/BeamNumber = Rt/RTION/BeamNumberToBeSimulated 69 | #s:Ge/RTION/BeamName = Rt/RTION/BeamNameToBeSimulated 70 | s:Ge/RTION/ImgDirectory = Rt/RTION/CTDirectory 71 | 72 | # 73 | #RotCollimator/Gantry/PatientSupport/IEC2DICOM are RTION specific 74 | d:Ge/RTION/RotCollimator = 0.0 deg 75 | d:Ge/RTION/RotGantry = 0.0 deg 76 | d:Ge/RTION/RotPatientSupport = 0.0 deg 77 | d:Ge/RTION/RotIEC2DICOM = 0.0 deg 78 | 79 | #TransX or ShiftX/TransX? 80 | d:Ge/RTION/TransX = 0 mm 81 | d:Ge/RTION/TransY = 0 mm 82 | d:Ge/RTION/TransZ = 0 mm 83 | 84 | #Material information for subcomponent 85 | s:Ge/RTION/rangeshifter/Material = "RS_Lucite" 86 | s:Ge/RTION/Block/Material = "G4_BRASS" 87 | s:Ge/RTION/Compensator/Material = "" 88 | s:Ge/RTION/Snout/Material = "" 89 | 90 | b:Ge/QuitIfOverlapDetected = "T" 91 | b:Ge/RTION/IsParallel = "F" 92 | b:Ge/RTION/Include = "T" 93 | 94 | # Changeable Parameters for setting other components 95 | # TOPAS extension will set up these parameters on-the-fly 96 | dc:Ge/RTION/IsoCenterX = 0 mm 97 | dc:Ge/RTION/IsoCenterY = 0 mm 98 | dc:Ge/RTION/IsoCenterZ = 0 mm 99 | 100 | dc:Ge/RTION/CollimatorAngle = 0 deg 101 | dc:Ge/RTION/GantryAngle = 0 deg 102 | dc:Ge/RTION/PatientSupportAngle = 0 deg 103 | dc:Ge/RTION/Iec2DicomAngle = 0 deg 104 | 105 | # Optional parameters 106 | b:Ge/RTION/IncludeSnoutIfExist = "T" 107 | b:Ge/RTION/IncludeRangeshifterIfExist = "T" 108 | b:Ge/RTION/IncludeBlockIfExist = "T" 109 | b:Ge/RTION/IncludeCompensatorIfExist = "T" 110 | 111 | 112 | ################################################### 113 | #-- RTION source 114 | ################################################### 115 | # Right handed coordinate 116 | s:So/RTION/Type = "TsRTIonSource" 117 | s:So/RTION/Component = "IEC_F" 118 | s:So/RTION/File = Rt/RTION/PlanFile 119 | i:So/RTION/BeamNumber = Rt/RTION/BeamNumberToBeSimulated 120 | #s:So/RTION/BeamName = Rt/RTION/BeamNameToBeSimulated 121 | d:So/RTION/SID = 39.0 cm #source to isocenter distance. 122 | 123 | # Translation w.r.t mother volume 124 | # ShiftX/Y/Z is RTION source specific parameters 125 | d:So/RTION/ShiftX = 0.0 mm 126 | d:So/RTION/ShiftY = 0.0 mm 127 | d:So/RTION/ShiftZ = 0.0 mm 128 | 129 | #RotCollimator/Gantry/PatientSupport/IEC2DICOM are RTION specific 130 | d:So/RTION/RotCollimator = 0.0 deg 131 | d:So/RTION/RotGantry = 0.0 deg 132 | d:So/RTION/RotPatientSupport = 0.0 deg 133 | d:So/RTION/RotIEC2DICOM = 0.0 deg 134 | 135 | # Changeable parameters set by 'TsRTIonSource' 136 | dc:So/RTION/IsoCenterX = 0 mm 137 | dc:So/RTION/IsoCenterY = 0 mm 138 | dc:So/RTION/IsoCenterZ = 0 mm 139 | 140 | # Parameters output by RTION_source 141 | dc:So/RTION/CollimatorAngle = 0 deg 142 | dc:So/RTION/Iec2DicomAngle = 0 deg 143 | dc:So/RTION/GantryAngle = 0 deg 144 | dc:So/RTION/PatientSupportAngle = 0 deg 145 | 146 | u:So/RTION/ParticlesPerHistory = Rt/RtION/ParticlesPerHistory 147 | 148 | i:Ts/ShowHistoryCountAtInterval = 10000 149 | b:Ts/ShowCPUTime = "T" 150 | #i:Ts/NumberOfThreads = 1 151 | #b:Ts/DumpParameters = "T" 152 | -------------------------------------------------------------------------------- /rti/treatment_machines/rbe/rbe_1p1.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_TREATMENT_MACHINE_RBE_1P1_H 2 | #define RTI_TREATMENT_MACHINE_RBE_1P1_H 3 | 4 | /// \file 5 | /// 6 | /// Treatment machine for Lunder proton center and TOPAS MC code 7 | 8 | #include 9 | 10 | namespace rti{ 11 | 12 | namespace rbe{ 13 | 14 | /// \class rbe_1p1 15 | /// represents beam model for Lunder IMPT machine in MGH 16 | template 17 | class rbe_1p1 : public treatment_machine_ion { 18 | protected: 19 | 20 | public: 21 | /// Default constructor 22 | rbe_1p1() 23 | { 24 | treatment_machine_ion::SAD_[0] = 1800.0; 25 | treatment_machine_ion::SAD_[1] = 2000.0; 26 | } 27 | 28 | ~rbe_1p1(){;} 29 | 30 | /// Characterize MODULATED_SPEC/UNIFORM 31 | /// \note not yet implemented cause we treat patients with spot-scanning only 32 | virtual 33 | size_t 34 | characterize_history( 35 | const rti::beam_module_ion::spot& s0, 36 | const rti::beam_module_ion::spot& s1, 37 | float scale) 38 | { 39 | (void)s0;//unused 40 | (void)s1;//unused 41 | (void)scale;//unused 42 | return 0; 43 | } 44 | 45 | /// Characterize MODULATED_SPEC/UNIFORM 46 | /// \note not yet implemented cause we treat patients with spot-scanning only 47 | virtual 48 | size_t 49 | characterize_history( 50 | const rti::beam_module_ion::spot& s, 51 | float scale) 52 | { 53 | return s.meterset / scale; 54 | } 55 | 56 | 57 | /// Characterize UNIFORM beam delivery continous scan 58 | /// define a continuous position distribution in rti_distributions 59 | /// this uses "phsp6d_fanbeam" distribution to sample position between x0 to x1. 60 | virtual 61 | rti::beamlet 62 | characterize_beamlet( 63 | const rti::beam_module_ion::spot& s0, 64 | const rti::beam_module_ion::spot& s1) 65 | { 66 | (void)s0;//unused 67 | (void)s1;//unused 68 | return rti::beamlet(); 69 | } 70 | 71 | /// Characterize beamlet for MODULATED beam 72 | virtual 73 | rti::beamlet 74 | characterize_beamlet(const rti::beam_module_ion::spot& s) 75 | { 76 | 77 | //Energy distribution 78 | // 1. constant energy 79 | auto energy = new rti::const_1d({s.e},{0}); 80 | 81 | // 2. X-Y position at at z 82 | rti::vec3 iso(s.x, s.y, 0); 83 | rti::vec3 beam = 84 | this->beam_starting_position(iso, 85 | rti::treatment_machine_ion::source_to_isocenter_mm_); 86 | rti::vec3 dir = iso - beam; 87 | dir.normalize(); 88 | 89 | // 3. Complete fluence distribution 90 | // this samples x, x', y, y', z, z' 91 | std::array spot_mean = {beam.x, beam.y, beam.z, dir.x, dir.y, dir.z}; 92 | std::array spot_sigm = {s.fwhm_x/T(2.355), s.fwhm_y/T(2.355), 0.0, 0.0, 0.0, 0.0}; 93 | std::array corr = {0.0, 0.0}; 94 | auto fluence= new rti::phsp_6d(spot_mean, spot_sigm, corr); 95 | 96 | return rti::beamlet(energy, fluence); 97 | } 98 | 99 | /// Characterize Rangeshifter 100 | rti::rangeshifter* 101 | characterize_rangeshifter( 102 | const rti::dataset* ds, 103 | rti::modality_type m) 104 | { 105 | auto seq_tags = &rti::seqtags_per_modality.at(m); 106 | 107 | //1. rangeshifter sequence 108 | // get a DICOM tag for given modality. 109 | auto rs_ds = (*ds)( seq_tags->at("rs")) ; 110 | assert(rs_ds.size() >=1); 111 | 112 | //2. Snout position from control point 0 113 | std::vector ftmp; 114 | auto layer0 = (*ds)(seq_tags->at("ctrl"))[0]; //layer0 for snout position 115 | layer0->get_values( "SnoutPosition", ftmp); 116 | 117 | rti::vec3 lxyz(300.0, 300.0, 0.0) ; 118 | rti::vec3 pxyz(0.0, 0.0, ftmp[0]) ; 119 | rti::mat3x3 rxyz(0.0, 0.0, 0.0) ; 120 | 121 | //3. range shifter sequence 122 | for(auto r : rs_ds){ 123 | std::vector rs_id(0); 124 | r->get_values("RangeShifterID" , rs_id); 125 | 126 | if ( !rs_id[0].compare("10mm")){ 127 | lxyz.z += 10.0; 128 | }else if ( !rs_id[0].compare("20mm")){ 129 | lxyz.z += 20.0; 130 | }else if ( !rs_id[0].compare("40mm")){ 131 | lxyz.z += 40.0; 132 | } 133 | assert(lxyz.z>0); 134 | } 135 | 136 | pxyz.z -= (lxyz.z + 5.0) ; //gap is 5 mm between snout downstream to rangeshifter upstream 137 | std::cout<<"Range shifter thickness: " << lxyz.z 138 | << " (mm) and position: " << pxyz.z <<" (mm)" << std::endl; 139 | 140 | return new rti::rangeshifter(lxyz, pxyz, rxyz); 141 | } 142 | 143 | /// Characterize aperture 144 | rti::aperture* 145 | characterize_aperture( 146 | const rti::dataset* ds, 147 | rti::modality_type m 148 | ){ 149 | //1. aperture opening points. 150 | auto xypts = this->characterize_aperture_opening(ds,m); 151 | 152 | //2. block sequence 153 | auto seq_tags = &rti::seqtags_per_modality.at(m); 154 | auto blk_ds = (*ds)( seq_tags->at("blk")) ; 155 | assert(blk_ds.size() >=1); 156 | 157 | std::vector ftmp; 158 | 159 | blk_ds[0]->get_values( "BlockThickness", ftmp); 160 | rti::vec3 lxyz(400.0, 400.0, ftmp[0]); 161 | 162 | blk_ds[0]->get_values("IsocenterToBlockTrayDistance", ftmp); 163 | rti::vec3 pxyz(0.0, 0.0, ftmp[0]+lxyz.z*0.5); 164 | 165 | rti::mat3x3 rxyz(0.0, 0.0, 0.0); 166 | 167 | return new rti::aperture(xypts, lxyz, pxyz, rxyz); 168 | } 169 | }; 170 | 171 | } 172 | } 173 | #endif 174 | -------------------------------------------------------------------------------- /rti/treatment_machines/rbe/rbe_1p1_complete.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_TREATMENT_MACHINE_RBE_1P1_H 2 | #define RTI_TREATMENT_MACHINE_RBE_1P1_H 3 | 4 | /// \file 5 | /// 6 | /// Treatment machine for Lunder proton center and TOPAS MC code 7 | 8 | #include 9 | 10 | namespace rti{ 11 | 12 | namespace rbe{ 13 | 14 | /// \class rbe_1p1 15 | /// represents beam model for Lunder IMPT machine in MGH 16 | template 17 | class rbe_1p1 : public treatment_machine_ion { 18 | protected: 19 | 20 | public: 21 | /// Default constructor 22 | rbe_1p1() 23 | { 24 | treatment_machine_ion::SAD_[0] = 1800.0; 25 | treatment_machine_ion::SAD_[1] = 2000.0; 26 | } 27 | 28 | ~rbe_1p1(){;} 29 | 30 | /// Characterize MODULATED_SPEC/UNIFORM 31 | /// \note not yet implemented cause we treat patients with spot-scanning only 32 | virtual 33 | size_t 34 | characterize_history( 35 | const rti::beam_module_ion::spot& s0, 36 | const rti::beam_module_ion::spot& s1, 37 | float scale) 38 | { 39 | return 0; 40 | } 41 | 42 | /// Characterize MODULATED_SPEC/UNIFORM 43 | /// \note not yet implemented cause we treat patients with spot-scanning only 44 | virtual 45 | size_t 46 | characterize_history( 47 | const rti::beam_module_ion::spot& s, 48 | float scale) 49 | { 50 | return s.meterset / scale; 51 | } 52 | 53 | 54 | /// Characterize UNIFORM beam delivery continous scan 55 | /// define a continuous position distribution in rti_distributions 56 | /// this uses "phsp6d_fanbeam" distribution to sample position between x0 to x1. 57 | virtual 58 | rti::beamlet 59 | characterize_beamlet( 60 | const rti::beam_module_ion::spot& s0, 61 | const rti::beam_module_ion::spot& s1) 62 | { 63 | return rti::beamlet(); 64 | } 65 | 66 | /// Characterize beamlet for MODULATED beam 67 | virtual 68 | rti::beamlet 69 | characterize_beamlet(const rti::beam_module_ion::spot& s) 70 | { 71 | 72 | /Energy distribution 73 | // 1. constant energy 74 | auto energy = new rti::const_1d({s.e},{0}); 75 | 76 | //Fluence distribution 77 | // 1. beamlet direction 78 | rti::vec3 dir(std::atan(s.x/treatment_machine_ion::SAD_[0]), 79 | std::atan(s.y/treatment_machine_ion::SAD_[1]), 80 | -1.0); 81 | 82 | // 2. new x-y position at source plane 83 | rti::vec3 pos(0, 0, rti::treatment_machine_ion::source_to_isocenter_mm_); 84 | pos.x = (treatment_machine_ion::SAD_[0] - pos.z) * dir.x ; 85 | pos.y = (treatment_machine_ion::SAD_[1] - pos.z) * dir.y ; 86 | 87 | // 3. Complete fluence distribution 88 | // this samples x, x', y, y', z, z' 89 | std::array spot_mean = {pos.x, pos.y, pos.z, dir.x, dir.y, -1}; 90 | std::array spot_sigm = {s.fwhm_x/T(2.355), s.fwhm_y/T(2.355), 0.0, 0.0, 0.0, 0.0}; 91 | std::array corr = {0.0, 0.0}; 92 | auto fluence= new rti::phsp_6d(spot_mean, spot_sigm, corr); 93 | 94 | return rti::beamlet(energy, fluence); 95 | } 96 | 97 | /// Characterize Rangeshifter 98 | rti::rangeshifter* 99 | characterize_rangeshifter( 100 | const rti::dataset* ds, 101 | rti::modality_type m) 102 | { 103 | auto seq_tags = &rti::seqtags_per_modality.at(m); 104 | 105 | //1. rangeshifter sequence 106 | // get a DICOM tag for given modality. 107 | auto rs_ds = (*ds)( seq_tags->at("rs")) ; 108 | assert(rs_ds.size() >=1); 109 | 110 | //2. Snout position from control point 0 111 | std::vector ftmp; 112 | auto layer0 = (*ds)(seq_tags->at("ctrl"))[0]; //layer0 for snout position 113 | layer0->get_values( "SnoutPosition", ftmp); 114 | 115 | rti::vec3 lxyz(300.0, 300.0, 0.0) ; 116 | rti::vec3 pxyz(0.0, 0.0, ftmp[0]) ; 117 | rti::mat3x3 rxyz(0.0, 0.0, 0.0) ; 118 | 119 | //3. range shifter sequence 120 | for(auto r : rs_ds){ 121 | std::vector rs_id(0); 122 | r->get_values("RangeShifterID" , rs_id); 123 | 124 | if ( !rs_id[0].compare("10mm")){ 125 | lxyz.z += 10.0; 126 | }else if ( !rs_id[0].compare("20mm")){ 127 | lxyz.z += 20.0; 128 | }else if ( !rs_id[0].compare("40mm")){ 129 | lxyz.z += 40.0; 130 | } 131 | assert(lxyz.z>0); 132 | } 133 | 134 | pxyz.z -= (lxyz.z + 5.0) ; //gap is 5 mm between snout downstream to rangeshifter upstream 135 | std::cout<<"Range shifter thickness: " << lxyz.z 136 | << " (mm) and position: " << pxyz.z <<" (mm)" << std::endl; 137 | 138 | return new rti::rangeshifter(lxyz, pxyz, rxyz); 139 | } 140 | 141 | /// Characterize aperture 142 | rti::aperture* 143 | characterize_aperture( 144 | const rti::dataset* ds, 145 | rti::modality_type m 146 | ){ 147 | //1. aperture opening points. 148 | auto xypts = this->characterize_aperture_opening(ds,m); 149 | 150 | //2. block sequence 151 | auto seq_tags = &rti::seqtags_per_modality.at(m); 152 | auto blk_ds = (*ds)( seq_tags->at("blk")) ; 153 | assert(blk_ds.size() >=1); 154 | 155 | std::vector ftmp; 156 | 157 | blk_ds[0]->get_values( "BlockThickness", ftmp); 158 | rti::vec3 lxyz(400.0, 400.0, ftmp[0]); 159 | 160 | blk_ds[0]->get_values("IsocenterToBlockTrayDistance", ftmp); 161 | rti::vec3 pxyz(0.0, 0.0, ftmp[0]+lxyz.z*0.5); 162 | 163 | rti::mat3x3 rxyz(0.0, 0.0, 0.0); 164 | 165 | return new rti::aperture(xypts, lxyz, pxyz, rxyz); 166 | } 167 | }; 168 | 169 | } 170 | } 171 | #endif 172 | -------------------------------------------------------------------------------- /rti/base/rti_rtdose.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_RTDOSE_H 2 | #define RTI_RTDOSE_H 3 | 4 | /// \file 5 | /// 6 | /// DICOM-RT dose 7 | 8 | #include 9 | 10 | namespace rti{ 11 | 12 | /// \class rtdose 13 | /// rtdose has a float as pixel type. 14 | /// \tparam R for grid coordinate (float or double) a type of x, y, and z positions 15 | template 16 | class rtdose : public rect3d { 17 | protected: 18 | 19 | /// path to rtdose file 20 | char* rtdose_file; 21 | 22 | /// Dimension of rtdose cube 23 | rti::vec3 lxyz; 24 | 25 | public: 26 | /// Default constructor 27 | CUDA_HOST 28 | rtdose(){;} 29 | 30 | /// Constructs a rectlinear grid from array of x/y/z with their size 31 | /// \param f rtdose file name. 32 | CUDA_HOST 33 | rtdose(std::string f) 34 | { 35 | rtdose_file = new char[f.length()+1]; 36 | strcpy(rtdose_file, f.c_str()); 37 | 38 | gdcm::ImageReader reader; 39 | reader.SetFileName(rtdose_file); 40 | reader.Read(); 41 | const gdcm::Image& img = reader.GetImage(); 42 | 43 | /// We assumed that dose grid has same voxel size, 44 | /// especially we assumed that Z framebuffer is same 45 | /// Direction cosine is assumed to be (1,0,0,0,1,0) 46 | auto xyz_mm = img.GetOrigin() ; 47 | auto dxyz_mm = img.GetSpacing() ; 48 | auto nxyz = img.GetDimensions(); 49 | //std::cout<< img << std::endl; 50 | 51 | lxyz.x = dxyz_mm[0] * nxyz[0]; 52 | lxyz.y = dxyz_mm[1] * nxyz[1]; 53 | lxyz.z = dxyz_mm[2] * nxyz[2]; 54 | 55 | rect3d::dim_.x = nxyz[0]; 56 | rect3d::dim_.y = nxyz[1]; 57 | rect3d::dim_.z = nxyz[2]; 58 | 59 | /// Initializes x_,y_,z_ vector 60 | rect3d::x_ = new R[rect3d::dim_.x]; 61 | rect3d::y_ = new R[rect3d::dim_.y]; 62 | rect3d::z_ = new R[rect3d::dim_.z]; 63 | 64 | for(size_t i=0; i < rect3d::dim_.x ; ++i) rect3d::x_[i] = xyz_mm[0] + i*dxyz_mm[0]; 65 | for(size_t i=0; i < rect3d::dim_.y ; ++i) rect3d::y_[i] = xyz_mm[1] + i*dxyz_mm[1]; 66 | 67 | const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); 68 | 69 | //gdcm::Attribute<0x0028,0x0009> frame_increment_ptr ; 70 | //frame_increment_ptr.SetFromDataElement(ds.GetDataElement(frame_increment_ptr.GetTag())); 71 | //assert(frame_increment_ptr.GetValue() == gdcm::Tag(0x3004,0x000c) && "GridFrameOffsetVector is missing."); 72 | 73 | gdcm::Attribute<0x3004,0x000c> gridframe_offsetvector ; 74 | gridframe_offsetvector.SetFromDataElement(ds.GetDataElement(gridframe_offsetvector.GetTag())); 75 | auto offset_vector = gridframe_offsetvector.GetValues(); 76 | auto offset_size = gridframe_offsetvector.GetNumberOfValues(); 77 | 78 | for(size_t i=0; i < offset_size ; ++i) rect3d::z_[i] = xyz_mm[2] + offset_vector[i]; 79 | 80 | std::cout<<"RTDOSE (nx,ny,nz): (" << nxyz[0] << ", " << nxyz[1] <<", " << nxyz[2] <<")" << std::endl; 81 | std::cout<<"RTDOSE (dx,dy,dz): (" << dxyz_mm[0] << ", " << dxyz_mm[1] <<", " << dxyz_mm[2] <<")" << std::endl; 82 | std::cout<<"RTDOSE (x,y,z): (" << rect3d::x_[0] << ", " << rect3d::y_[0] <<", " << rect3d::z_[0] <<")" << std::endl; 83 | } 84 | 85 | 86 | 87 | /// Initializes data by reading PixelData in RTDOSE 88 | /// This operation needs to be done in CPU side 89 | CUDA_HOST 90 | virtual void 91 | load_data() 92 | { 93 | size_t nb_voxels = rect3d::dim_.x * rect3d::dim_.y * rect3d::dim_.z; 94 | rect3d::data_.resize(nb_voxels); 95 | 96 | gdcm::ImageReader reader; 97 | reader.SetFileName(rtdose_file); 98 | reader.Read(); 99 | const gdcm::Image& img = reader.GetImage(); 100 | float intercept = float(img.GetIntercept()); 101 | float slope = float(img.GetSlope()); 102 | 103 | gdcm::PixelFormat pixeltype = img.GetPixelFormat(); 104 | 105 | switch( pixeltype ) 106 | { 107 | case gdcm::PixelFormat::INT8: 108 | { 109 | std::valarray d(nb_voxels) ; 110 | img.GetBuffer((char*) &d[0]); 111 | this->transform_to_float(d, intercept, slope); 112 | } 113 | break; 114 | case gdcm::PixelFormat::UINT8: 115 | { 116 | std::valarray d(nb_voxels) ; 117 | img.GetBuffer((char*) &d[0]); 118 | this->transform_to_float(d, intercept, slope); 119 | } 120 | break; 121 | case gdcm::PixelFormat::INT16: 122 | { 123 | std::valarray d(nb_voxels) ; 124 | img.GetBuffer((char*) &d[0]); 125 | this->transform_to_float(d, intercept, slope); 126 | } 127 | break; 128 | case gdcm::PixelFormat::UINT16: 129 | { 130 | std::valarray d(nb_voxels) ; 131 | img.GetBuffer((char*) &d[0]); 132 | this->transform_to_float(d, intercept, slope); 133 | } 134 | break; 135 | case gdcm::PixelFormat::INT32: 136 | { 137 | std::valarray d(nb_voxels) ; 138 | img.GetBuffer((char*) &d[0]); 139 | this->transform_to_float(d, intercept, slope); 140 | } 141 | break; 142 | case gdcm::PixelFormat::UINT32: 143 | { 144 | //Only this Pixelformat was tested. 145 | //couldn't put buffer to rect3d img.GetBuffer( (char*) &rect3d::data_[0] ); 146 | std::valarray d(nb_voxels) ; 147 | img.GetBuffer((char*) &d[0]); 148 | this->transform_to_float(d, intercept, slope); 149 | } 150 | break; 151 | default: 152 | assert(0); 153 | } 154 | 155 | } 156 | 157 | 158 | 159 | /// Converts integer type PixelData to float 160 | /// by using std::transform 161 | CUDA_HOST 162 | template 163 | void 164 | transform_to_float( 165 | std::valarray& in, 166 | float inter, 167 | float slope) 168 | { 169 | std::transform(begin(in), end(in), //from 170 | begin(rect3d::data_), //to 171 | [inter, slope](S a) { return (float(a))*slope + inter; } 172 | ); 173 | } 174 | 175 | /// Returns the size of rtdose box 176 | CUDA_HOST 177 | rti::vec3 178 | get_dosegrid_size(){ 179 | return lxyz; 180 | } 181 | 182 | }; 183 | 184 | 185 | 186 | } 187 | 188 | #endif -------------------------------------------------------------------------------- /rti/base/rti_ct.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_CT_H 2 | #define RTI_CT_H 3 | 4 | /// \file 5 | /// 6 | /// A 3D image grid with int16 as a pixel. 7 | 8 | #include "gdcmScanner.h" 9 | #include "gdcmAttribute.h" 10 | #include "gdcmDirectory.h" 11 | #include "gdcmIPPSorter.h" 12 | #include "gdcmImageReader.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace rti{ 18 | 19 | /// \class ct 20 | /// this ct class is a int16_t pixel type. 21 | /// \tparam R for grid coordinate (float or double) a type of x, y, and z positions 22 | template 23 | class ct : public rect3d { 24 | protected: 25 | 26 | std::vector files_ ; ///< DICOM image files sorted in Z acsending order 27 | 28 | std::map uid2file_ ; ///< SOP instance UID to id in files_ 29 | 30 | char* ct_dir {nullptr}; ///< directory for CT files 31 | 32 | R dx_; ///< pixel size in X 33 | R dy_; ///< pixel size in Y 34 | 35 | public: 36 | 37 | /// Default constructor 38 | CUDA_HOST 39 | ct(){;} 40 | 41 | ~ct() { delete[] ct_dir; } 42 | 43 | /// Constructs a rectlinear grid from array of x/y/z with their size 44 | /// \param f CT directory 45 | /// \param is_print set true if you want to print out files (UNUSED) 46 | /// \note this method sets only dimensions and extensions. 47 | /// \see load_data() to read in pixel data 48 | CUDA_HOST 49 | ct( 50 | std::string f, 51 | bool is_print=false) 52 | { 53 | (void)is_print;//unused 54 | ct_dir = new char[f.length()+1]; 55 | strcpy(ct_dir, f.c_str()); 56 | 57 | //http://gdcm.sourceforge.net/html/SortImage_8cxx-example.html#_a5 58 | gdcm::Directory dir; 59 | dir.Load(ct_dir, false); ///< non-recursive 60 | 61 | const gdcm::Directory::FilenamesType& all_files = dir.GetFilenames(); 62 | 63 | gdcm::Scanner scanner ; 64 | const gdcm::Tag ct_tag = gdcm::Tag(0x08, 0x60); 65 | scanner.AddTag(ct_tag); 66 | scanner.Scan(all_files); 67 | 68 | auto ct_files = scanner.GetAllFilenamesFromTagToValue(ct_tag, "CT" ); 69 | 70 | gdcm::IPPSorter ippsorter; 71 | ippsorter.SetComputeZSpacing(false); 72 | ippsorter.Sort(ct_files); ///< asending along z 73 | files_ = ippsorter.GetFilenames(); 74 | 75 | gdcm::Scanner s; 76 | s.AddTag( gdcm::Tag(0x0008,0x0018) ); ///< SOP instance UID 77 | s.AddTag( gdcm::Tag(0x0020,0x0032) ); ///< Image Position (Patient) 78 | s.AddTag( gdcm::Tag(0x0028,0x0010) ); ///< Rows 79 | s.AddTag( gdcm::Tag(0x0028,0x0011) ); ///< Columns 80 | s.AddTag( gdcm::Tag(0x0028,0x0030) ); ///< Pixel spacing 81 | 82 | if (!s.Scan( files_ )) assert("scan fail."); 83 | 84 | size_t nx = 0; ///< columns 85 | size_t ny = 0; ///< rows 86 | size_t nz = files_.size() ; ///< number of images. 87 | rect3d::z_ = new R[nz]; 88 | rect3d::dim_.z = nz; 89 | double x0{0}; 90 | double y0{0}; 91 | 92 | for(size_t i = 0 ; i < nz ; ++i){ 93 | gdcm::Scanner::TagToValue const &m0 = s.GetMapping(files_[i].c_str()); 94 | 95 | std::string img_position(m0.find(gdcm::Tag(0x0020,0x0032))->second); 96 | unsigned int deli0 = img_position.find_first_of( '\\' ); 97 | unsigned int deli1 = img_position.find_last_of( '\\' ); 98 | rect3d::z_[i] = (R) (std::stod( img_position.substr(deli1+1) )); 99 | 100 | ///< We only determine rows, colums, x0, y0, dx, and dy with first image 101 | if(i==0){ 102 | x0 = std::stod(img_position.substr(0,deli0)); 103 | y0 = std::stod(img_position.substr(deli0+1, deli1-deli0)); 104 | 105 | ny = std::stoi(m0.find(gdcm::Tag(0x0028,0x0010))->second); 106 | nx = std::stoi(m0.find(gdcm::Tag(0x0028,0x0011))->second); 107 | rect3d::dim_.x = nx; 108 | rect3d::dim_.y = ny; 109 | std::string pixel_spacing(m0.find(gdcm::Tag(0x0028,0x0030))->second) ; 110 | unsigned int deli = pixel_spacing.find_first_of( '\\' ); 111 | dx_ = std::stod(pixel_spacing.substr(0, deli)); 112 | dy_ = std::stod(pixel_spacing.substr(deli+1)); 113 | 114 | } 115 | 116 | ///< A map to search file path upon instance UID 117 | uid2file_.insert(std::make_pair(m0.find(gdcm::Tag(0x0008,0x0018))->second, files_[i])); 118 | } 119 | 120 | rect3d::x_ = new R[nx]; 121 | for(size_t i = 0 ; i < nx ; ++i){ 122 | rect3d::x_[i] = x0 + dx_ * i; 123 | } 124 | rect3d::y_ = new R[nx]; 125 | for(size_t i = 0 ; i < ny ; ++i){ 126 | rect3d::y_[i] = y0 + dy_ * i; 127 | } 128 | std::cout<<"CT (nx,ny,nz): (" << nx << ", " << ny <<", " << nz <<")" << std::endl; 129 | std::cout<<"CT (dx,dy,dz): (" << dx_ << ", " << dy_ <<", " << rect3d::z_[1] - rect3d::z_[0] <<")" << std::endl; 130 | std::cout<<"CT (x,y,z): (" << rect3d::x_[0] 131 | << ", " << rect3d::y_[0] 132 | <<", " << rect3d::z_[0] << ")" << std::endl; 133 | 134 | } 135 | 136 | /// Load patient's image to volume 137 | CUDA_HOST 138 | virtual 139 | void 140 | load_data() 141 | { 142 | size_t nb_voxels_2d = rect3d::dim_.x * rect3d::dim_.y ; 143 | size_t nb_voxels_3d = nb_voxels_2d * rect3d::dim_.z; 144 | 145 | rect3d::data_.resize(nb_voxels_3d); 146 | float intercept = 0; 147 | float slope = 1; 148 | 149 | for(size_t i=0 ; i < rect3d::dim_.z; ++i){ 150 | 151 | gdcm::ImageReader reader; 152 | reader.SetFileName(files_[i].c_str()); 153 | reader.Read(); 154 | const gdcm::Image& img = reader.GetImage(); 155 | 156 | //n_x * n_y * bytes = img.GetBufferLength() 157 | intercept = float(img.GetIntercept()); 158 | slope = float(img.GetSlope()); 159 | 160 | gdcm::PixelFormat pixeltype = img.GetPixelFormat(); 161 | 162 | switch( pixeltype ) 163 | { 164 | case gdcm::PixelFormat::INT16: 165 | { 166 | img.GetBuffer((char*) &rect3d::data_[i*nb_voxels_2d]); 167 | } 168 | break; 169 | default: 170 | assert(0); 171 | }//switch 172 | 173 | }//for 174 | rect3d::data_ = rect3d::data_*int16_t(slope) + intercept; 175 | } 176 | 177 | /// Returns x-index for given x position 178 | inline virtual 179 | size_t 180 | find_c000_x_index(const R& x) 181 | { 182 | assert( (x >= rect3d::x_[0]) && (x < rect3d::x_[rect3d::dim_.x-1]) ); 183 | assert( dx_ > 0 ); 184 | return floor(x/dx_); 185 | } 186 | 187 | /// Returns y-index for given y position 188 | inline virtual 189 | size_t 190 | find_c000_y_index(const R& y) 191 | { 192 | assert( (y >= rect3d::y_[0]) && (y < rect3d::y_[rect3d::dim_.y-1]) ); 193 | assert( dy_ > 0 ); 194 | return floor(y/dy_); 195 | } 196 | 197 | /// A friend function to copy CT's grid information 198 | /// \param src CT grid information to be copied 199 | /// \param dest rect3d will have same coordinate system with src 200 | /// \tparam R0 grid type of CT grid 201 | /// \tparam T1 pixel type of dest grid 202 | /// \tparam R1 pixel type of dest grid 203 | template 204 | friend void clone_ct_structure(ct& src, rect3d& dest); 205 | }; 206 | 207 | 208 | } 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /rti/test/session/cli_rti.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLI_RTI_HPP 2 | #define CLI_RTI_HPP 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | //#include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | namespace rti{ 24 | 25 | /** 26 | * A command line interface for Unit tests 27 | * cli is a top virtual class 28 | * 1. reading RT-Ion plan file and its type (plan or log). 29 | * 2. creating a geometries, patient, dosegrid, and beamline components of a machine 30 | * 3. creating beam sources of a machine 31 | */ 32 | class cli{ 33 | 34 | protected: 35 | std::map > parameters; 36 | 37 | public: 38 | cli(){;}; 39 | ~cli(){;} 40 | 41 | void 42 | read(int argc, char** argv){ 43 | 44 | std::cout<<"# of arguments: "<< argc<second.push_back(argv[j]) ; 56 | j++; 57 | }while( j < argc ); 58 | //Print out options 59 | std::cout<first<<" : " ; 60 | for(auto parm:it->second) std::cout<< parm <<" "; 61 | std::cout< 68 | operator[]( 69 | const std::string& t) 70 | { 71 | return parameters[t]; 72 | } 73 | 74 | virtual void print_help(char* s){;} 75 | 76 | }; 77 | 78 | 79 | 80 | /** 81 | * A command line interface for Unit tests of patient geometry 82 | * 83 | */ 84 | class cli_patient : public cli{ 85 | 86 | public: 87 | cli_patient(){ 88 | parameters = 89 | std::map > 90 | ({ 91 | //option name, {parameters} 92 | {"--ctdir" ,{} } 93 | }); 94 | } 95 | 96 | ~cli_patient(){;} 97 | 98 | virtual void 99 | print_help( 100 | char* s 101 | ) 102 | { 103 | std::cout<<"Usage: "< > 120 | ({ 121 | //option name, {parameters} 122 | {"--ctdir" ,{} }, 123 | {"--dosefile" ,{} }, 124 | {"--pxyz" ,{} } 125 | }); 126 | } 127 | 128 | ~cli_dosegrid(){;} 129 | 130 | virtual void 131 | print_help( 132 | char* s 133 | ) 134 | { 135 | std::cout<<"Usage: "< > 155 | ({ 156 | //option name, {parameters} 157 | {"--ctdir" ,{} }, 158 | {"--rtdose" ,{} }, 159 | {"--dvf" ,{} }, 160 | {"--output" ,{}} 161 | }); 162 | } 163 | 164 | ~cli_dvf(){;} 165 | 166 | virtual void 167 | print_help( 168 | char* s 169 | ) 170 | { 171 | std::cout<<"Usage: "<> 189 | ({ 190 | //option name, {parameters} 191 | {"--rti" ,{} }, //RTIP or RTIBTR 192 | {"--bname" ,{} }, //beam name 193 | {"--bnumber" ,{} }, //beam number 194 | {"--machine" ,{} } //specify machine name to use 195 | }); 196 | } 197 | ~cli_rti_read(){;} 198 | 199 | virtual void 200 | print_help( 201 | char* s 202 | ) 203 | { 204 | std::cout<<"Usage: "< >({ 222 | //option name, {parameters} 223 | {"--rti" ,{} }, //RTIP or RTIBTR 224 | {"--machine" ,{} }, //treatment machine: Institution:Tx_machine_name 225 | {"--mc_code" ,{} }, //mc_code, e.g., topas:3.0.1 (default), gpmc 226 | {"--bname" ,{} }, //beam name 227 | {"--bnumber" ,{} }, //beam number 228 | {"--spots" ,{} }, //spot-id, obsolute, will be replaced by beamlets 229 | {"--beamlets" ,{} }, //beamlet-id 230 | {"--pph" ,{} }, //particles_per_history 231 | {"--pxyz" ,{} }, //position xyz w.r.t mother coordinate system 232 | {"--rxyz" ,{} }, //rotation xyz w.r.t mother coordinate system 233 | {"--sid" ,{} }, //beam generation distance from isocenter. 234 | {"--output" ,{} } //output file name, for empty, such as "", it printout to console 235 | }); 236 | } 237 | 238 | ~cli_beam_read(){;} 239 | 240 | virtual void 241 | print_help( 242 | char* s 243 | ) 244 | { 245 | std::cout<<"Usage: "< 1 histories 254 | std::cout<<" "<<"--pxyz x y z"< 9 | #include 10 | 11 | #include 12 | 13 | namespace rti{ 14 | 15 | /// \class vec2 16 | /// a vector with two position 17 | /// \tparam T type of vector elements 18 | template 19 | class vec2 { 20 | public: 21 | // 22 | T x; 23 | T y; 24 | 25 | CUDA_HOST_DEVICE 26 | vec2(vec2& ref){ 27 | x = ref.x; 28 | y = ref.y; 29 | } 30 | 31 | CUDA_HOST_DEVICE 32 | vec2(): x(0), y(0){;} 33 | 34 | CUDA_HOST_DEVICE 35 | vec2(T a, T b): x(a), y(b){;} 36 | 37 | CUDA_HOST_DEVICE 38 | vec2(const vec2& ref ): x(ref.x), y(ref.y){;} 39 | 40 | 41 | CUDA_HOST 42 | vec2(const std::array& ref ): x(ref[0]), y(ref[1]){;} 43 | //#endif 44 | 45 | CUDA_HOST_DEVICE 46 | ~vec2(){;} 47 | 48 | CUDA_HOST_DEVICE 49 | #if defined(__CUDACC__) 50 | //sqrtf : for float, sqrtg: for double 51 | T norm()const{return sqrtf(x*x+y*y);} 52 | #else 53 | T norm()const{return std::sqrt(x*x+y*y);} 54 | #endif 55 | 56 | CUDA_HOST_DEVICE 57 | T dot(const vec2& v)const{ 58 | return x*v.x + y*v.y; 59 | } 60 | 61 | //cross product of 2d vec is scalar 62 | CUDA_HOST_DEVICE 63 | T 64 | cross(const vec2& v)const{ 65 | return x*v.y - y*v.x; 66 | } 67 | 68 | CUDA_HOST_DEVICE 69 | vec2& 70 | operator= 71 | (const vec2& r){ 72 | x = r.x ; y = r.y; 73 | return *this; 74 | } 75 | 76 | CUDA_HOST_DEVICE 77 | vec2 78 | operator + 79 | (const vec2& r)const{ 80 | return vec2(x+r.x, y+r.y); 81 | } 82 | 83 | CUDA_HOST_DEVICE 84 | vec2 85 | operator - 86 | (const vec2& r)const{ 87 | return vec2(x-r.x, y-r.y); 88 | } 89 | 90 | CUDA_HOST_DEVICE 91 | vec2 92 | operator * 93 | (const T& r)const{ 94 | return vec2(x*r, y*r); 95 | } 96 | 97 | template 98 | vec2 99 | operator * 100 | (const R& r)const{ 101 | return vec2(x*r, y*r); 102 | } 103 | 104 | CUDA_HOST_DEVICE 105 | vec2 106 | operator * 107 | (const vec2& r)const{ 108 | return vec2(x*r.x, y*r.y); 109 | } 110 | 111 | CUDA_HOST_DEVICE 112 | void dump() const { 113 | printf("(x,y): (%f, %f)\n", x,y); 114 | } 115 | 116 | }; 117 | 118 | /// \class vec3 119 | /// a vector with three position 120 | /// \tparam T type of vector elements 121 | //this is a copy of HepRotation. 122 | template 123 | class vec3 { 124 | public: 125 | // 126 | T x; 127 | T y; 128 | T z; 129 | 130 | CUDA_HOST_DEVICE 131 | vec3(vec3& ref){ 132 | x = ref.x; 133 | y = ref.y; 134 | z = ref.z; 135 | } 136 | 137 | CUDA_HOST_DEVICE 138 | vec3(): x(0), y(0), z(0){;} 139 | 140 | CUDA_HOST_DEVICE 141 | vec3(T a, T b, T c): x(a), y(b), z(c){;} 142 | 143 | CUDA_HOST_DEVICE 144 | vec3(const vec3& ref ): x(ref.x), y(ref.y), z(ref.z){;} 145 | 146 | CUDA_HOST 147 | vec3(const std::array& ref ): x(ref[0]), y(ref[1]), z(ref[2]){;} 148 | 149 | CUDA_HOST_DEVICE 150 | vec3(const T* ref ): x(ref[0]), y(ref[1]), z(ref[2]){;} 151 | 152 | CUDA_HOST_DEVICE 153 | ~vec3(){;} 154 | 155 | CUDA_HOST_DEVICE 156 | #if defined(__CUDACC__) 157 | //sqrtf : for float, sqrtg: for double 158 | T norm()const{return sqrtf(x*x+y*y+z*z);} 159 | #else 160 | T norm()const{return std::sqrt(x*x+y*y+z*z);} 161 | #endif 162 | 163 | CUDA_HOST_DEVICE 164 | #if defined(__CUDACC__) 165 | //sqrtf : for float, sqrtg: for double 166 | void normalize(){ 167 | T n = sqrtf(x*x+y*y+z*z); 168 | x /= n; 169 | y /= n; 170 | z /= n; 171 | } 172 | #else 173 | void normalize(){ 174 | T n = std::sqrt(x*x+y*y+z*z); 175 | x /= n; 176 | y /= n; 177 | z /= n; 178 | } 179 | #endif 180 | 181 | CUDA_HOST_DEVICE 182 | vec3 183 | operator + 184 | (const vec3& r) const { 185 | return vec3( 186 | x + r.x, 187 | y + r.y, 188 | z + r.z 189 | ); 190 | } 191 | 192 | CUDA_HOST_DEVICE 193 | vec3 194 | operator - 195 | (const vec3& r) const { 196 | return vec3( 197 | x - r.x, 198 | y - r.y, 199 | z - r.z 200 | ); 201 | } 202 | 203 | CUDA_HOST_DEVICE 204 | vec3 205 | operator * 206 | (const T& r)const{ 207 | return vec3( 208 | x * r, 209 | y * r, 210 | z * r 211 | ); 212 | } 213 | 214 | CUDA_HOST_DEVICE 215 | vec3 216 | operator * 217 | (const T& r){ 218 | return vec3( 219 | x * r, 220 | y * r, 221 | z * r 222 | ); 223 | } 224 | 225 | CUDA_HOST_DEVICE 226 | vec3 227 | operator / 228 | (const T& r)const{ 229 | return vec3( 230 | x / r, 231 | y / r, 232 | z / r 233 | ); 234 | } 235 | 236 | CUDA_HOST_DEVICE 237 | T dot( 238 | const vec3& v)const{ 239 | return x*v.x + y*v.y + z*v.z; 240 | } 241 | 242 | CUDA_HOST_DEVICE 243 | vec3 244 | cross 245 | (const vec3& r) const { 246 | return vec3( 247 | y*r.z - z*r.y, 248 | z*r.x - x*r.z, 249 | x*r.y - y*r.x 250 | ); 251 | } 252 | 253 | 254 | CUDA_HOST_DEVICE 255 | vec3& 256 | operator= 257 | (const vec3& r){ 258 | x = r.x ; y = r.y; z = r.z; 259 | return *this; 260 | } 261 | 262 | CUDA_HOST_DEVICE 263 | vec3& 264 | operator+= 265 | (const vec3& r){ 266 | x += r.x ; y += r.y; z += r.z; 267 | return *this; 268 | } 269 | 270 | CUDA_HOST_DEVICE 271 | void dump() const { 272 | #if defined(__CUDACC__) 273 | printf("x,y,z: (%f, %f, %f)\n", x,y,z); 274 | #else 275 | std::cout<<"x,y,z: ("<< x <<", " << y <<", " << z <<") " << std::endl; 276 | #endif 277 | } 278 | }; 279 | 280 | /// \class vec4 281 | /// a vector with four position 282 | /// \tparam T type of vector elements 283 | //this is a copy of HepRotation. 284 | template 285 | class vec4 { 286 | public: 287 | // 288 | T x; 289 | T y; 290 | T z; 291 | T s; //scale 292 | 293 | CUDA_HOST_DEVICE 294 | vec4(vec4& ref){ 295 | x = ref.x; 296 | y = ref.y; 297 | z = ref.z; 298 | s = ref.s; 299 | } 300 | 301 | CUDA_HOST_DEVICE 302 | vec4(): x(0), y(0), z(0), s(0){;} 303 | 304 | CUDA_HOST_DEVICE 305 | vec4(T a, T b, T c, T d): x(a), y(b), z(c), s(d){;} 306 | 307 | CUDA_HOST_DEVICE 308 | vec4(const vec4& ref ): x(ref.x), y(ref.y), z(ref.z), s(ref.s) {;} 309 | 310 | CUDA_HOST_DEVICE 311 | vec4(const T* ref ): x(ref[0]), y(ref[1]), z(ref[2]), s(ref[3]) {;} 312 | 313 | CUDA_HOST 314 | vec4(const std::array& ref ): x(ref[0]), y(ref[1]), z(ref[2]), s(ref[3]) {;} 315 | //#endif 316 | 317 | CUDA_HOST_DEVICE 318 | ~vec4(){;} 319 | 320 | CUDA_HOST_DEVICE 321 | #if defined(__CUDACC__) 322 | //sqrtf : for float, sqrtg: for double 323 | T norm()const{return sqrtf(x*x+y*y+z*z+s*s);} 324 | #else 325 | T norm()const{return std::sqrt(x*x+y*y+z*z+s*s);} 326 | #endif 327 | 328 | CUDA_HOST_DEVICE 329 | vec4 330 | operator + 331 | (const vec4& r) const { 332 | return vec4( 333 | x + r.x, 334 | y + r.y, 335 | z + r.z, 336 | s + r.s 337 | ); 338 | } 339 | 340 | CUDA_HOST_DEVICE 341 | vec4 342 | operator - 343 | (const vec4& r) const { 344 | return vec4( 345 | x - r.x, 346 | y - r.y, 347 | z - r.z, 348 | s - r.s 349 | ); 350 | } 351 | 352 | CUDA_HOST_DEVICE 353 | vec4 354 | operator * 355 | (const T& r)const{ 356 | return vec4( 357 | x * r, 358 | y * r, 359 | z * r, 360 | s * r 361 | ); 362 | } 363 | 364 | CUDA_HOST_DEVICE 365 | void dump() const 366 | { 367 | printf("(x,y,z,s): (%f, %f, %f)\n",x,y,z,s); 368 | } 369 | }; 370 | 371 | } 372 | 373 | #endif 374 | -------------------------------------------------------------------------------- /rti/test/session/treatment_session.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include "cli_rti.hpp" 8 | 9 | 10 | using namespace std; 11 | 12 | //typedef double phase_space_type; 13 | typedef float phase_space_type; 14 | 15 | 16 | void describe(const rti::dataset* beam); 17 | void describe_rtibtr(const rti::dataset* beam); 18 | 19 | int main(int argc, char** argv){ 20 | 21 | rti::cli_beam_read cl_opts; 22 | cl_opts.read(argc, argv); 23 | 24 | std::string machine_name = cl_opts["--machine"].size() == 0 ? "" : cl_opts["--machine"][0]; 25 | 26 | std::string mc_code = cl_opts["--mc_code"].size() == 0 ? "topas:3.2.0" : cl_opts["--mc_code"][0]; 27 | 28 | std::unique_ptr> 29 | treatment_session_(new rti::treatment_session(cl_opts["--rti"][0], machine_name, mc_code)); 30 | 31 | treatment_session_->summary(); 32 | 33 | rti::vec3(1.0,1.0,0.1); 34 | 35 | /* 36 | position displacement vector 37 | */ 38 | rti::vec3 p_xyz_(0,0,0); 39 | if( cl_opts["--pxyz"].size() >=1 ){ 40 | p_xyz_.x = std::stof(cl_opts["--pxyz"][0]); 41 | p_xyz_.y = std::stof(cl_opts["--pxyz"][1]); 42 | p_xyz_.z = std::stof(cl_opts["--pxyz"][2]); 43 | } 44 | 45 | //local rotation to account gantry rotation, couch rotation, couch pitch (better check). 46 | rti::mat3x3 r_xyz_(0,0,0); 47 | if( cl_opts["--rxyz"].size() >=1 ){ 48 | rti::vec3 rad ; 49 | rad.x = M_PI*std::stof(cl_opts["--rxyz"][0])/180.0; 50 | rad.y = M_PI*std::stof(cl_opts["--rxyz"][1])/180.0; 51 | rad.z = M_PI*std::stof(cl_opts["--rxyz"][2])/180.0; 52 | r_xyz_ = rti::mat3x3(rad.x, rad.y, rad.z); 53 | } 54 | 55 | //particles per history 56 | double particles_per_history = -1; //generate 1 history per beamlet 57 | if (cl_opts["--pph"].size()>=1) particles_per_history = std::stod(cl_opts["--pph"][0]); 58 | 59 | //source to isocenter distance (mm) 60 | float sid = 100.0 ; 61 | if (cl_opts["--sid"].size()>=1) sid = std::stof(cl_opts["--sid"][0]); 62 | 63 | //coordinate system: translational & rotational 64 | rti::coordinate_transform p_coord; 65 | 66 | //Objects set by either beam name or beam number 67 | rti::beamsource beam_src; 68 | rti::beamline beam_line; 69 | 70 | if( cl_opts["--bname"].size() >=1 ){ 71 | //if( cl_opts["--bname"].size() >=1 ){ 72 | std::string bname = cl_opts["--bname"][0]; 73 | p_coord = treatment_session_->get_coordinate(bname); 74 | beam_src = treatment_session_->get_beamsource(bname, p_coord, particles_per_history, sid); 75 | beam_line = treatment_session_->get_beamline(bname); 76 | } 77 | 78 | if( cl_opts["--bnumber"].size() >=1 ){ 79 | //if( cl_opts["--bnumber"].size() >=1 ){ 80 | int bnb = std::stoi(cl_opts["--bnumber"][0]); 81 | p_coord = treatment_session_->get_coordinate(bnb); 82 | beam_src = treatment_session_->get_beamsource(bnb, p_coord, particles_per_history, sid); 83 | beam_line = treatment_session_->get_beamline(bnb); 84 | } 85 | 86 | p_coord.dump(); 87 | std::cout<<"gantry rotation: "< start_id); 119 | 120 | 121 | /* 122 | * To generate 2.6M history, it took about 2 sec in CPU & memory usage was < 7 MB 123 | * The memory usage doesn't change with number of histories. 124 | */ 125 | std::cout<< "The size of source object: " 126 | << sizeof(beam_src) 127 | << ", total history:" 128 | << beam_src.total_histories()<< std::endl; 129 | 130 | std::queue< rti::vertex_t > histories; 131 | 132 | 133 | for(size_t current_id = start_id ; current_id < end_id ; ++current_id){ 134 | auto beamlet = beam_src[current_id]; 135 | auto beamlet_distribution = std::get<0>(beamlet); 136 | size_t histories_of_beamlet = std::get<1>(beamlet); 137 | 138 | while(histories_of_beamlet--){ 139 | auto h = beamlet_distribution(); 140 | histories.push(h); 141 | } 142 | } 143 | 144 | std::cout<<"Number of of histories in queue: "<< histories.size() << std::endl; 145 | const auto size_of_history = (sizeof(phase_space_type)+2*sizeof(rti::vec3)); 146 | std::cout<<"Byte size of the queue: "<< histories.size()*size_of_history << std::endl; 147 | 148 | std::ofstream output; 149 | 150 | if( cl_opts["--output"].size() >=1 ){ 151 | 152 | if( cl_opts["--output"][0].compare("")) output.open(cl_opts["--output"][0]); 153 | 154 | std::ostream& out = cl_opts["--output"][0].compare("") ? output : std::cout; 155 | 156 | while(!histories.empty()){ 157 | auto h = histories.front(); 158 | out<< h.pos.x <<" "<< h.pos.y <<" "<< h.pos.z<< " " 159 | << h.dir.x << " " << h.dir.y << " " << h.dir.z << " " 160 | << h.ke << std::endl; 161 | histories.pop(); 162 | } 163 | } 164 | 165 | return 0; 166 | 167 | } 168 | 169 | void describe(const rti::dataset* beam){ 170 | std::cout << "======== BEAM info =======" << std::endl; 171 | std::vector data_int; 172 | std::vector data_int_tag; 173 | std::vector data_float; 174 | std::vector data_str; 175 | 176 | beam->get_values("BeamNumber", data_int); 177 | std::cout<< "BeamNumber: " << data_int[0] << std::endl; 178 | 179 | beam->get_values("BeamName", data_str); 180 | std::cout<< "BeamName: " << data_str[0] << std::endl; 181 | 182 | beam->get_values("BeamType", data_str); 183 | std::cout<< "BeamType: " << data_str[0] << std::endl; 184 | 185 | beam->get_values("TreatmentDeliveryType", data_str); 186 | std::cout<<"TreatmentDeliveryType : " << data_str[0] << std::endl; 187 | 188 | beam->get_values("NumberOfWedges", data_int); 189 | std::cout <<"NumberOfWedges: " << data_int[0] << std::endl; 190 | 191 | beam->get_values("NumberOfRangeShifters", data_int); 192 | std::cout <<"NumberOfRangeShifters: " << data_int[0] << std::endl; 193 | 194 | beam->get_values("NumberOfCompensators", data_int); 195 | std::cout <<"NumberOfCompensators : " << data_int[0] << std::endl; 196 | 197 | beam->get_values("NumberOfBoli", data_int); 198 | std::cout <<"Number Of Boli : " << data_int[0] << std::endl; 199 | 200 | beam->get_values("NumberOfBlocks", data_int); 201 | std::cout <<"NumberOfBlocks : " << data_int[0] << std::endl; 202 | 203 | beam->get_values("NumberOfControlPoints", data_int); 204 | std::cout <<"NumberOfControlPoints : " << data_int[0] << std::endl; 205 | 206 | beam->get_values("VirtualSourceAxisDistances", data_float); 207 | std::cout <<"VirtualSourceAxisDistances : " << data_float[0] <<", " << data_float[1] << std::endl; 208 | 209 | } 210 | 211 | 212 | void describe_rtibtr(const rti::dataset* beam){ 213 | std::cout << "======== BEAM info RTIBTR =======" << std::endl; 214 | std::vector data_int; 215 | std::vector data_int_tag; 216 | std::vector data_float; 217 | std::vector data_str; 218 | 219 | //beam->get_values("BeamNumber", data_int); 220 | //std::cout<< "BeamNumber: " << data_int[0] << std::endl; 221 | 222 | beam->get_values("BeamName", data_str); 223 | std::cout<< "BeamName: " << data_str[0] << std::endl; 224 | 225 | beam->get_values("BeamType", data_str); 226 | std::cout<< "BeamType: " << data_str[0] << std::endl; 227 | 228 | beam->get_values("TreatmentDeliveryType", data_str); 229 | std::cout<<"TreatmentDeliveryType : " << data_str[0] << std::endl; 230 | 231 | beam->get_values("NumberOfWedges", data_int); 232 | std::cout <<"NumberOfWedges: " << data_int[0] << std::endl; 233 | 234 | beam->get_values("NumberOfRangeShifters", data_int); 235 | std::cout <<"NumberOfRangeShifters: " << data_int[0] << std::endl; 236 | 237 | beam->get_values("NumberOfCompensators", data_int); 238 | std::cout <<"NumberOfCompensators : " << data_int[0] << std::endl; 239 | 240 | beam->get_values("NumberOfBoli", data_int); 241 | std::cout <<"Number Of Boli : " << data_int[0] << std::endl; 242 | 243 | beam->get_values("NumberOfBlocks", data_int); 244 | std::cout <<"NumberOfBlocks : " << data_int[0] << std::endl; 245 | 246 | beam->get_values("NumberOfControlPoints", data_int); 247 | std::cout <<"NumberOfControlPoints : " << data_int[0] << std::endl; 248 | 249 | //beam->get_values("VirtualSourceAxisDistances", data_float); 250 | //std::cout <<"VirtualSourceAxisDistances : " << data_float[0] <<", " << data_float[1] << std::endl; 251 | 252 | } 253 | -------------------------------------------------------------------------------- /rti/base/rti_treatment_session.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_TREATMENT_SESSION_HPP 2 | #define RTI_TREATMENT_SESSION_HPP 3 | 4 | /// \file 5 | /// 6 | /// Treatment session 7 | 8 | #include 9 | #include 10 | 11 | #include "gdcmReader.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | //generic treatment machine 18 | #include 19 | 20 | 21 | //Custom treatment machines 22 | #include 23 | 24 | namespace rti { 25 | 26 | /// \class treatment_session 27 | /// \tparam T type of phase-space variables 28 | /// Reads RT-Ion file, creates treatment_machine, 29 | /// and returns machine objects, geometry, source, and coordinate system. 30 | /// treatment_session is an entry point to RT-Ion interface to a MC engine. 31 | /// \note we are considering to include patient, and dosegrid here. 32 | template 33 | class treatment_session { 34 | protected: 35 | 36 | ///< Sequence tag dictionary for modality specific 37 | const std::map< 38 | const std::string, 39 | const gdcm::Tag 40 | >* seq_tags_ ; 41 | 42 | ///< RT Modality type, e.g., RTPLAN, RTRECORD, IONPLAN, IONRECORD 43 | rti::modality_type mtype_ ; 44 | 45 | ///< machine name, e.g., institution_name:machine_name 46 | std::string machine_name_ ; 47 | 48 | rti::treatment_machine* tx_machine_ = nullptr; 49 | 50 | ///< top level DICOM dataset, either RTIP or RTIBTR 51 | rti::dataset* rti_ds_ = nullptr; 52 | 53 | public: 54 | 55 | /// Constructs treatment machine based on DICOM or specific file name. 56 | /// It reads in RT file recursively and construct a dataset tree 57 | /// Depending on RTIP or RTIBTR, it copies a propriate DICOM tag dictionaries 58 | /// (seqtags_per_modality). 59 | /// 60 | /// \param file_for_tx_machine : RTPLAN, IONPLAN, RTRECORD, IONRECORD 61 | /// Currently IONPLAN and IONRECORD are supported only. 62 | treatment_session( 63 | std::string file_for_tx_machine, //for beamline and source, 64 | std::string m_name = "", 65 | std::string mc_code = "topas:3.x") 66 | { 67 | 68 | gdcm::Reader reader; 69 | 70 | reader.SetFileName(file_for_tx_machine.c_str()); 71 | 72 | const bool is_file_valid = reader.Read(); 73 | if(!is_file_valid) throw std::runtime_error("Invalid DICOM file is given to treatment_session."); 74 | 75 | gdcm::MediaStorage ms; 76 | ms.SetFromFile(reader.GetFile()); 77 | 78 | switch(ms){ 79 | case gdcm::MediaStorage::RTPlanStorage : 80 | mtype_ = RTPLAN; 81 | break; 82 | //case gdcm::MediaStorage::RTBeamsTreatmentRecordStorage : 83 | //gdcm doesn't have definition of RTBeamsTreatmentRecordStorge 84 | //case gdcm::MediaStorage::RTBeamsTreatmentRecordStorage : //1.2.840.10008.5.1.4.1.1.481.4 85 | // mtype_ = RTRECORD; 86 | // break; 87 | case gdcm::MediaStorage::RTIonPlanStorage : 88 | mtype_ = IONPLAN; 89 | break; 90 | case gdcm::MediaStorage::RTIonBeamsTreatmentRecordStorage : 91 | mtype_ = IONRECORD; 92 | break; 93 | default: 94 | throw std::runtime_error("treatment_session does not supports given RTMODALITY"); 95 | } 96 | 97 | rti_ds_ = new rti::dataset(reader.GetFile().GetDataSet(), true); 98 | seq_tags_ = &rti::seqtags_per_modality.at(mtype_); 99 | 100 | ///< machine name is set 101 | if( !m_name.compare("") ){ 102 | ///< we assume machine name is in 1-st beam sequence 103 | ///< This part doesn't work for RTIBTR 104 | const rti::dataset* beam_ds; 105 | if (mtype_ == IONPLAN){ 106 | beam_ds = (*rti_ds_)( seq_tags_->at("beam") )[0]; 107 | }else if( mtype_ == IONRECORD){ 108 | beam_ds = (*rti_ds_)( seq_tags_->at("machine") )[0]; 109 | }else{ 110 | throw std::runtime_error("treatment_session can't find machine name and institute."); 111 | } 112 | 113 | std::vector in ; beam_ds->get_values("InstitutionName", in); 114 | std::vector bn ; beam_ds->get_values("TreatmentMachineName" , bn); 115 | 116 | if(in.size()>0 && bn.size()>0) 117 | { 118 | machine_name_ = rti::trim_copy(in[0]) + ":" + rti::trim_copy(bn[0]); 119 | } 120 | else if(in.size()>0) 121 | { 122 | machine_name_ = rti::trim_copy(in[0]); 123 | } 124 | else if(bn.size()>0) 125 | { 126 | machine_name_ = rti::trim_copy(bn[0]); 127 | } 128 | 129 | }else{ 130 | machine_name_ = m_name; 131 | std::cout<create_machine(machine_name_, mc_code)){ 135 | std::runtime_error("No MC machine is registered for "+machine_name_); 136 | } 137 | 138 | } 139 | 140 | 141 | /// Creates rti::machine and return true for sucessful creation or false. 142 | /// \param machine_name for machine name 143 | /// \param mc_code for mc engine, e.g., code:version 144 | /// \note it takes itype_ member variables. caution, itype_ shouldn't be changed after creation. 145 | /// \note we have a branch for machines based on "string" comparison. 146 | /// Looking for better way to determine during 'ideally' pre-processing. 147 | /// type_traits allows to branch the logic flow based on the type of variables. 148 | bool 149 | create_machine 150 | (std::string machine_name, 151 | std::string mc_code) 152 | { 153 | if(tx_machine_){ 154 | throw std::runtime_error("Preexisting machine."); 155 | } 156 | std::cout<<"machine_name: "<(model); 171 | return true; 172 | }else if(!site.compare("rbe") ){ 173 | if ( !model.compare("1.1") ){ 174 | tx_machine_ = new rti::rbe::rbe_1p1; 175 | return true; 176 | } 177 | else{ 178 | throw std::runtime_error("Valid machine is not available."); 179 | } 180 | 181 | }else{ 182 | throw std::runtime_error("Valid site is not available."); 183 | } 184 | 185 | return false; 186 | } 187 | 188 | /// Default destructor 189 | ~treatment_session() 190 | { 191 | delete tx_machine_; 192 | delete rti_ds_; 193 | } 194 | 195 | /* 196 | const 197 | std::shared_ptr 198 | get_dosegrid(std::shared_ptr p) 199 | { dosegrid_->set_from_patient(p); 200 | return dosegrid_; 201 | } 202 | */ 203 | 204 | /// Returns a list of beam names present in the plan file. 205 | std::vector 206 | get_beam_names() { 207 | auto beam_sequence = (*rti_ds_)( seq_tags_->at("beam") ); 208 | std::vector beam_names; 209 | for (const auto &beam : beam_sequence) { 210 | std::vector tmp; 211 | beam->get_values("BeamName", tmp); 212 | beam_names.push_back(tmp[0]); 213 | } 214 | return beam_names; 215 | } 216 | 217 | 218 | /// Search and return a beam (DICOM dataset) in BeamSequence for given beam name 219 | /// \param bnm for beam name 220 | /// \return rti::dataset* constant pointer. 221 | const 222 | rti::dataset* 223 | get_beam_dataset(std::string bnm) 224 | { 225 | auto bseq = (*rti_ds_)( seq_tags_->at("beam") ); 226 | for(auto i : bseq){ 227 | std::vector bn ; 228 | i->get_values("BeamName" , bn); //works for RTIP & RTIBTR 229 | if(bn.size()==0) continue; 230 | if (bnm == rti::trim_copy(bn[0])) { 231 | return i ; 232 | } 233 | } 234 | throw std::runtime_error("Invalid beam name."); 235 | } 236 | 237 | /// Search and return a beam (DICOM dataset) in BeamSequence for given beam number 238 | /// \param bnm for beam number 239 | /// \return rti::dataset* constant pointer. 240 | const 241 | rti::dataset* 242 | get_beam_dataset(int bnb) 243 | { 244 | auto bseq = (*rti_ds_)( seq_tags_->at("beam") ); 245 | for(auto i : bseq){ 246 | //i->dump(); 247 | std::vector bn ; 248 | i->get_values( "BeamNumber" , bn); //works only for RTIP 249 | assert(bn.size()>0); 250 | if (bnb == bn[0]){ 251 | return i ; 252 | } 253 | } 254 | throw std::runtime_error("Invalid beam number."); 255 | } 256 | 257 | 258 | /// Get beamline object for given beam id, e.g, beam name or beam number 259 | /// \param beam_id for beam number or beam name 260 | /// \return beamline object. 261 | template 262 | rti::beamline 263 | get_beamline(S beam_id) 264 | { 265 | return tx_machine_->create_beamline( 266 | this->get_beam_dataset(beam_id), 267 | mtype_); 268 | } 269 | 270 | /// Gets beam source object for given beam id, e.g, beam name or beam number 271 | /// \param beam_id for beam number or beam name 272 | /// \param coord for coordinate transformation 273 | /// \param sid for source to isocenter distance in mm 274 | /// \param scale for calculating number of histories to be simulated from beamlet weight 275 | /// \return beamsource object. 276 | template 277 | rti::beamsource 278 | get_beamsource 279 | ( S beam_id, 280 | const rti::coordinate_transform coord, 281 | float scale, 282 | T sid) 283 | { 284 | return tx_machine_->create_beamsource( 285 | this->get_beam_dataset(beam_id), 286 | mtype_, 287 | coord, 288 | scale, 289 | sid); 290 | } 291 | 292 | /// Gets time line object for given beam id, e.g., beam name or number 293 | /// \param beam_id 294 | template 295 | std::map 296 | get_timeline(S beam_id) 297 | { 298 | return tx_machine_->create_timeline( this->get_beam_dataset(beam_id), 299 | mtype_); 300 | } 301 | 302 | /// Gets beam coordinate object for given beam id, e.g, beam name or beam number 303 | /// \param beam_id for beam number or beam name 304 | /// \return beamsource object. 305 | template 306 | rti::coordinate_transform 307 | get_coordinate(S beam_id){ 308 | return tx_machine_->create_coordinate_transform( this->get_beam_dataset(beam_id), 309 | mtype_); 310 | } 311 | 312 | /// Summarize plan 313 | /// \param bnb for beam number 314 | void 315 | summary(void){ 316 | rti_ds_->dump(); 317 | } 318 | 319 | /// Return ion type 320 | /// \return rti::m_type_ 321 | rti::modality_type 322 | get_modality_type(void){ 323 | return mtype_ ; 324 | } 325 | 326 | }; 327 | 328 | } 329 | 330 | #endif 331 | -------------------------------------------------------------------------------- /rti/base/rti_treatment_machine_ion.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_TREATMENT_MACHINE_ION_H 2 | #define RTI_TREATMENT_MACHINE_ION_H 3 | 4 | /// \file 5 | /// 6 | /// Treatment machine for particle therapy 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SIGMA2FWHM 2.35482004503 // 2.*std::sqrt(2.*std::log(2.)) 14 | 15 | namespace rti{ 16 | 17 | /// \class treatment_machine_ion 18 | /// 19 | /// Describes an particle therapy system 20 | /// \tparam T type of phase-space variables, e.g., float or double 21 | template 22 | class treatment_machine_ion : public treatment_machine { 23 | 24 | protected: 25 | 26 | public: 27 | /// Default constructor 28 | treatment_machine_ion(){;} 29 | 30 | /// Default Destructors 31 | ~treatment_machine_ion(){;} 32 | 33 | /* 34 | /// Method to check scan mode 35 | beam_ds->get_values("ScanMode" , sm); 36 | if(in.size()>0) machine_name += rti::trim_copy(in[0]) + ":"; 37 | if (bn.size() > 0 && sm.size() > 0 ){ 38 | auto ictrl = (*beam_ds)( seq_tags_->at("ctrl")); 39 | std::vector tn; 40 | for(auto j: ictrl){ 41 | j->get_values("ScanSpotTuneID", tn); 42 | if (tn.size()>0){ 43 | 44 | machine_name += 45 | rti::trim_copy(bn[0]) + ":" + 46 | rti::trim_copy(sm[0]) + ":" + 47 | rti::trim_copy(tn[0]) ; 48 | break; 49 | } 50 | }//delivery 51 | } 52 | */ 53 | 54 | /// Returns angles of Collimator, Gantry, and Couch and iso-center position 55 | /// \note rotation angle directio is assumed CCW 56 | /// As RTIBTR doesn't have iso-center position, (0,0,0) is returned for RTIBTR 57 | virtual 58 | rti::coordinate_transform 59 | create_coordinate_transform( 60 | const rti::dataset* ds, 61 | const rti::modality_type m) 62 | { 63 | std::cout<<"create_coordinate_transform:"<at("ctrl"))[0]; //layer0 67 | 68 | std::vector tmp; 69 | std::vector tmp_dir; 70 | std::array angles; 71 | ///< As CW, CRW, NONE, conditionally required, we don't use them at this moment 72 | layer0->get_values( "BeamLimitingDeviceAngle", tmp); 73 | angles[0] = tmp[0]; 74 | //layer0->get_values( "BeamLimitingDeviceRotationDirection", tmp_dir); 75 | 76 | layer0->get_values( "GantryAngle", tmp); 77 | //layer0->get_values( "GantryRotationDirection", tmp_dir); 78 | angles[1] = tmp[0]; 79 | 80 | layer0->get_values( "PatientSupportAngle", tmp); 81 | //layer0->get_values( "PatientSupportRotationDirection", tmp_dir); 82 | angles[2] = tmp[0]; 83 | angles[3] = 0.0; 84 | 85 | rti::vec3 pos; 86 | 87 | ///< Rotation and Position don't exist in RTRECORD and IONRECORD 88 | if( (m == RTPLAN) || (m == IONPLAN) ){ 89 | layer0->get_values( "IsocenterPosition", tmp); 90 | pos.x = tmp[0]; 91 | pos.y = tmp[1]; 92 | pos.z = tmp[2]; 93 | } 94 | 95 | return rti::coordinate_transform(angles, pos); 96 | } 97 | 98 | 99 | /// Returns beamsource object 100 | /// \param ds one-item of IonBeamSequence 101 | /// \param m modality type, e.g., RTIP or RTIBTR 102 | /// \param pcoord coordinate transform to map global coordinate system 103 | /// \param scalefactor a downscale factor, i.e., particles per history. 104 | /// -1 means any of beamlet generates one history (usefule for debugging). 105 | /// \param source_to_isocenter_mm distance the histories are generated. 106 | /// \note user don't have to touch this part typically. 107 | /// \note currently we support only MODULATED beam 108 | /// \note maybe return const rti::beamsource& ? 109 | /// 110 | virtual 111 | rti::beamsource 112 | create_beamsource( 113 | const rti::dataset* ds, 114 | const rti::modality_type m, 115 | const rti::coordinate_transform pcoord, 116 | const float scalefactor = -1, 117 | const float source_to_isocenter_mm = 390.0) 118 | { 119 | 120 | treatment_machine::source_to_isocenter_mm_ = source_to_isocenter_mm; 121 | 122 | ///< Parse DICOM beam module for ION 123 | //auto seq_tags = &rti::seqtags_per_modality.at(m); 124 | //auto ictrl = (*ds)(seq_tags->at("ctrl")); 125 | //beam_module_ion ion_beam(ictrl, m); 126 | beam_module_ion ion_beam(ds, m); 127 | 128 | std::vector scan_mode(1); 129 | ds->get_values("ScanMode",scan_mode); 130 | //ds->get_values("SAD",?);? 131 | 132 | if( !scan_mode[0].compare("MODULATED") ){ 133 | std::runtime_error("Only MODULATED scan mode is supported"); 134 | //scan_mode[0].compare("UNIFORM") 135 | //scan_mode[0].compare("MODULATED_SPEC") 136 | //this->create_modulated_mixed(scalefactor); 137 | } 138 | 139 | rti::beamsource beamsource; 140 | 141 | ///< Modulated BEAM 142 | const auto& spots = *(ion_beam.get_sequence()); 143 | const size_t nb_spots = spots.size(); 144 | 145 | for(size_t i = 0 ; i < nb_spots ; ++i){ 146 | /// Calculate number of histories to be simulated per beamlet 147 | size_t nb_histories = 148 | (scalefactor == -1) ? 1 : this->characterize_history(spots[i], scalefactor); 149 | 150 | /// Calculate on & off time per beamlet 151 | /// By default, on is set to 1 sec but off is set to 0 sec. 152 | std::array time_on_off ; 153 | 154 | if( i == (nb_spots - 1)){ 155 | time_on_off = this->characterize_beamlet_time(spots[i], spots[i]); 156 | }else{ 157 | time_on_off = this->characterize_beamlet_time(spots[i], spots[i+1]); 158 | } 159 | 160 | /// Then, add a beamlet with 161 | /// its number of histories, 162 | /// coordinate system 163 | /// beamlet time on/off 164 | beamsource.append_beamlet(this->characterize_beamlet(spots[i]), 165 | nb_histories, 166 | pcoord, 167 | time_on_off[0], 168 | time_on_off[1]); 169 | 170 | } 171 | return beamsource; 172 | } 173 | 174 | 175 | /// User method to characterize MODULATED beamlet based on spot information from DICOM. 176 | virtual 177 | rti::beamlet 178 | characterize_beamlet(const rti::beam_module_ion::spot& s) = 0; 179 | 180 | /// User method to characterize beam delivery time 181 | /// on_time, off_time by default 1 sec and 0 sec 182 | virtual 183 | std::array 184 | characterize_beamlet_time( 185 | const rti::beam_module_ion::spot& s_current, 186 | const rti::beam_module_ion::spot& s_next) 187 | { 188 | (void)s_current;//unused 189 | (void)s_next;//unused 190 | return {1.0, 0.0}; 191 | } 192 | // const bool meterset_is_mu = false 193 | 194 | /// User method to characterize UNIFORM/MODULATED_SPEC beamlet based on spot information from DICOM. 195 | virtual 196 | rti::beamlet 197 | characterize_beamlet( 198 | const rti::beam_module_ion::spot& s0, 199 | const rti::beam_module_ion::spot& s1) = 0; 200 | 201 | /// User method to characterize number of histories per MODULATED beamlet 202 | /// based on spot information from DICOM. 203 | virtual 204 | size_t 205 | characterize_history( 206 | const rti::beam_module_ion::spot& s, 207 | float scale) 208 | { 209 | return s.meterset / scale; 210 | } 211 | 212 | /// User method to characterize number of histories per UNIFORM/MODULATED_SPEC beamlet 213 | /// based on spot information from DICOM. 214 | virtual 215 | size_t 216 | characterize_history( 217 | const rti::beam_module_ion::spot& s0, 218 | const rti::beam_module_ion::spot& s1, 219 | float scale) 220 | { 221 | (void)s0;//unused 222 | return s1.meterset / scale; 223 | } 224 | 225 | 226 | /// Returns beamline object 227 | /// \param ds one-item of IonBeamSequence 228 | /// \param m modality type, e.g., RTIP or RTIBTR 229 | /// \note Users don't have to reimplement this method typically. 230 | /// \note maybe return const rti::beamline& ? 231 | /// \note coordinate_transform is not implemented here 232 | /// \note coordinate_transform is handled in MC engine, i.e., TOPAS by now. 233 | /// \note it's not yet clear whether to include coordinate_transform like create_beamsource 234 | /// \note currently we consider range-shiter and aperture. geometry will be added later. 235 | virtual 236 | rti::beamline 237 | create_beamline( 238 | const rti::dataset* ds, 239 | rti::modality_type m) 240 | { 241 | 242 | rti::beamline beamline; 243 | 244 | ///< Access to tag LUT 245 | //auto seq_tags = &rti::seqtags_per_modality.at(m); 246 | 247 | ///< geometry creation of snout? 248 | ///< position from control point 0 249 | ///< beamline.append_geometry(this->characterize_snout); 250 | std::vector itmp; 251 | std::vector ftmp; 252 | 253 | ///< 1. number of rangeshifter sequence 254 | ds->get_values( "NumberOfRangeShifters", itmp); 255 | std::cout<<"number of range shifter: " << itmp[0] << std::endl; 256 | if(itmp[0]>=1){ 257 | beamline.append_geometry( 258 | this->characterize_rangeshifter(ds, m) 259 | ); 260 | } 261 | 262 | ///< 2. number of blocks 263 | ds->get_values( "NumberOfBlocks", itmp); 264 | std::cout<<"number of blocks: " << itmp[0] << std::endl; 265 | if(itmp[0]>=1){ 266 | 267 | beamline.append_geometry( 268 | this->characterize_aperture(ds,m) 269 | ); 270 | 271 | } 272 | return beamline; 273 | } 274 | 275 | /// Returns rangeshifter 276 | /// \param ds one-item of IonBeamSequence 277 | /// \param m modality type, e.g., RTIP or RTIBTR 278 | /// \note Users need to implement their own rule to convert DICOM info to RS specification. 279 | virtual 280 | rti::rangeshifter* 281 | characterize_rangeshifter( 282 | const rti::dataset* ds, 283 | rti::modality_type m) = 0 ; 284 | 285 | /// Returns aperture 286 | /// \param ds one-item of IonBeamSequence 287 | /// \param m modality type, e.g., RTIP or RTIBTR 288 | /// \note Users need to implement their own rule to convert DICOM info to RS specification. 289 | virtual 290 | rti::aperture* 291 | characterize_aperture( 292 | const rti::dataset* ds, 293 | rti::modality_type m 294 | )=0 ; 295 | 296 | /// Returns set of (x,y) points for aperture openning. 297 | /// \param ds one-item of IonBeamSequence 298 | /// \param m modality type, e.g., RTIP or RTIBTR 299 | /// \note Users need to implement their own rule to convert DICOM info to APT specification. 300 | /// \note multiple holes are supported. 301 | const std::vector< std::vector>> 302 | characterize_aperture_opening( 303 | const rti::dataset* ds, 304 | rti::modality_type m) 305 | { 306 | std::vector< 307 | std::vector> 308 | > apt_xy_points; 309 | auto seq_tags = &rti::seqtags_per_modality.at(m); 310 | 311 | //0. aperture sequence 312 | auto apt_ds = (*ds)( seq_tags->at("blk")) ; 313 | assert(apt_ds.size() >=1); 314 | 315 | for(auto apt : apt_ds){ 316 | std::vector> block_data; 317 | std::vector nb_xy_points; 318 | std::vector xy_points; 319 | 320 | apt->get_values( "BlockNumberOfPoints", nb_xy_points ); 321 | apt->get_values( "BlockData", xy_points ); 322 | 323 | for(int j=0; j < nb_xy_points[0] ; ++j){ 324 | block_data.push_back({xy_points[j*2],xy_points[j*2+1]}); 325 | } 326 | apt_xy_points.push_back(block_data); 327 | } 328 | return apt_xy_points; 329 | } 330 | 331 | /// Returns set of (x,y) points at z-position. 332 | /// \param iso : isocenter position. iso.z is not read in by default. 333 | /// \param z : z-position where the beam starts 334 | virtual 335 | rti::vec3 336 | beam_starting_position( 337 | const rti::vec3& iso, 338 | T z) 339 | { 340 | rti::vec3 beam(0,0,z); 341 | beam.x = iso.x * (treatment_machine_ion::SAD_[0] - beam.z) / treatment_machine_ion::SAD_[0] ; 342 | beam.y = iso.y * (treatment_machine_ion::SAD_[1] - beam.z) / treatment_machine_ion::SAD_[1] ; 343 | 344 | return beam; 345 | } 346 | 347 | }; 348 | 349 | } 350 | 351 | #endif 352 | -------------------------------------------------------------------------------- /rti/topas/rtion/TsRTIonSource.cc: -------------------------------------------------------------------------------- 1 | // Particle Source for TsRTIonSource 2 | // This code implementation is the intellectual property of the MGH. 3 | // this is an user extension for RT-Ion plan (RTIP) and beam treatment record (RTIBTR) 4 | // by Jungwook Shin jshin13@mgh.harvard.edu 5 | 6 | //Headers for C library 7 | #include 8 | #include 9 | #include 10 | 11 | //Headers for C++ std library 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | //Headers for Geant4 20 | #include "G4SystemOfUnits.hh" 21 | #include "G4IonTable.hh" 22 | #include "G4RotationMatrix.hh" 23 | #include "G4UIcommand.hh" 24 | #include "G4SystemOfUnits.hh" 25 | #include "G4ExtrudedSolid.hh" 26 | #include "G4PVPlacement.hh" 27 | 28 | //Headers for TOPAS 29 | #include "TsParameterManager.hh" 30 | 31 | //Headers for extension 32 | #include "TsRTIonSource.hh" 33 | 34 | #ifdef TOPAS_MT 35 | #include "G4AutoLock.hh" 36 | namespace {G4Mutex move_to_nextspot = G4MUTEX_INITIALIZER;} 37 | #endif 38 | 39 | TsRTIonSource::TsRTIonSource(TsParameterManager* pM, 40 | TsSourceManager* sM, 41 | G4String name) 42 | :TsSource(pM, sM, name) 43 | { 44 | 45 | std::cout<<"Creating RTIon Source."<GetStringParameter(GetFullParmName("File")); 48 | 49 | G4String machine_name = ""; 50 | 51 | if ( fPm->ParameterExists(GetFullParmName("machinename")) ){ 52 | machine_name = fPm->GetStringParameter(GetFullParmName("machinename")) ; 53 | } 54 | 55 | rti_session_ = 56 | std::unique_ptr> 57 | (new rti::treatment_session(rt_ion_file, machine_name)); //topas version 58 | 59 | 60 | //ReadHistories will be accessed from RTIonSourceGenerator 61 | ReadHistories = std::bind( 62 | &TsRTIonSource::ReadHistoriesPerBeamlet, 63 | this, 64 | std::placeholders::_1); 65 | 66 | this->ResolveParameters(); 67 | } 68 | 69 | TsRTIonSource::~TsRTIonSource() {;} 70 | 71 | 72 | void 73 | TsRTIonSource::ResolveParameters() 74 | { 75 | 76 | /** 77 | * Particle type: proton (default) 78 | */ 79 | if(fPm->ParameterExists(GetFullParmName("beamparticle"))){ 80 | TsParticleDefinition resolvedDef = 81 | fPm->GetParticleDefinition(fPm->GetStringParameter(GetFullParmName("beamparticle"))); 82 | particle_definition_ = resolvedDef.particleDefinition; 83 | if (!particle_definition_) 84 | std::cerr << "Unknown particle type read from parameter = " << GetFullParmName("beamparticle") << std::endl; 85 | }else{ 86 | particle_definition_ = G4Proton::ProtonDefinition(); 87 | } 88 | 89 | /** 90 | * Beam id 91 | * \brief beam number (required) or beam name (optional) 92 | * If beam number is given, we ignore beam name. 93 | * When, beam name is used primarily in your clinic, it is important not to use beam number. 94 | * Because in paramter file chain, beam number might be defined elsewhere. 95 | */ 96 | rti::beam_id_type beam_id = {rti::beam_id_type::NUM, 1}; 97 | if ( fPm->ParameterExists(GetFullParmName("beamnumber")) ){ 98 | G4int bnb = fPm->GetIntegerParameter(GetFullParmName("beamnumber")); 99 | beam_id.number = bnb; 100 | }else{ 101 | if ( fPm->ParameterExists(GetFullParmName("beamname")) ){ 102 | G4String bname = fPm->GetStringParameter(GetFullParmName("beamname")) ; 103 | beam_id.type = rti::beam_id_type::STR; 104 | beam_id.name = bname.c_str(); 105 | }else{ 106 | std::cerr << " Neither BeamNumber nor BeamName was given." << std::endl; 107 | exit(1); 108 | } 109 | } 110 | 111 | 112 | /** 113 | * Export DICOM coordinate information and export as TOPAS parameters 114 | */ 115 | rti::coordinate_transform rt_coordinate_dicom; 116 | switch(beam_id.type){ 117 | case rti::beam_id_type::NUM: 118 | rt_coordinate_dicom = rti_session_->get_coordinate(beam_id.number); 119 | break; 120 | case rti::beam_id_type::STR: 121 | rt_coordinate_dicom = rti_session_->get_coordinate(beam_id.name); 122 | break; 123 | } 124 | this->ExportDICOMCoordinateToParameters(rt_coordinate_dicom); 125 | std::cout<<"isocenter: " << std::endl; 126 | rt_coordinate_dicom.translation.dump(); 127 | 128 | /** 129 | * SID: source to isocenter distance 130 | */ 131 | float sid_mm = 0.0*mm ; 132 | if(fPm->ParameterExists(GetFullParmName("sid"))){ 133 | sid_mm = fPm->GetDoubleParameter(GetFullParmName("sid"), "Length")/mm; 134 | } 135 | 136 | /** 137 | * patient's position information & dosegrid 138 | */ 139 | G4String transValue ; 140 | G4String parameterName ; 141 | 142 | if ( fPm->ParameterExists(GetFullParmName("imgdirectory"))){ 143 | //Writing img center should come before readign TransX/Y/Z 144 | G4String image_dir = fPm->GetStringParameter(GetFullParmName("imgdirectory")); 145 | 146 | struct stat ss; 147 | if (stat(image_dir.c_str(), &ss) == 0) //exist 148 | { 149 | //check imgdirectory is DIR 150 | (ss.st_mode & S_IFDIR) ? true : throw std::runtime_error("Error: ImgDirectory should be a directory"); 151 | 152 | //check # of files in the directory 153 | DIR* dir = opendir(image_dir.c_str()); 154 | size_t files = 0; 155 | struct dirent* ent ; 156 | while((ent = readdir(dir))) files++; 157 | closedir(dir); 158 | if(files>2){ // . and .. are counted. 159 | rti::ct patient_ct(image_dir); 160 | auto ct_center = patient_ct.get_center(); 161 | this->Wrap3Vector(ct_center, "ImgCenter", "mm"); 162 | } 163 | } 164 | } 165 | 166 | /** 167 | * Updated coordinate from TOPAS UI 168 | * Rotation of Gantry, Coli, Patient support, and iso-center shift 169 | */ 170 | rti::vec3 p_xyz; 171 | p_xyz.x = static_cast (fPm->GetDoubleParameter(GetFullParmName("ShiftX"), "Length")/mm); 172 | p_xyz.y = static_cast (fPm->GetDoubleParameter(GetFullParmName("ShiftY"), "Length")/mm); 173 | p_xyz.z = static_cast (fPm->GetDoubleParameter(GetFullParmName("ShiftZ"), "Length")/mm); 174 | 175 | //Geant4's rotation direction is same with IEC 176 | //i.e.: +angle -> CCW rotation viewing from the plus of rotating axis 177 | //TOPAS: CW viewing from +axis 178 | //RTI (DICOM): CW viewing from -axis 179 | 180 | //Angle order: 1,2,3,4 181 | std::array rotations; 182 | rotations[0] = static_cast (fPm->GetDoubleParameter(GetFullParmName("RotCollimator"), "Angle")/rad); 183 | rotations[1] = static_cast (fPm->GetDoubleParameter(GetFullParmName("RotGantry"), "Angle")/rad); 184 | rotations[2] = static_cast (fPm->GetDoubleParameter(GetFullParmName("RotPatientSupport"), "Angle")/rad); 185 | rotations[3] = static_cast (fPm->GetDoubleParameter(GetFullParmName("RotIEC2DICOM"), "Angle")/rad); 186 | 187 | std::cout<<"RTION source coordinate position (x,y,z): " << std::endl; 188 | std::cout<<"RTION source Rotation (colli, gantry, patient support, iec2dicom): " 189 | << rotations[0]/deg <<", " 190 | << rotations[1]/deg <<", " 191 | << rotations[2]/deg <<", " 192 | << rotations[3]/deg << std::endl; 193 | 194 | rti::coordinate_transform rt_coordinate_topas(rotations, p_xyz); 195 | rt_coordinate_topas.rotation.dump(); 196 | 197 | /** 198 | * Particles per history 199 | * 200 | */ 201 | G4double particles_per_history = fPm->GetUnitlessParameter(GetFullParmName("particlesperhistory")); 202 | assert( (particles_per_history==0) || (particles_per_history==-1) || (particles_per_history>0) ); 203 | 204 | switch(beam_id.type){ 205 | case rti::beam_id_type::NUM: 206 | beam_source_ = rti_session_->get_beamsource( 207 | beam_id.number, 208 | rt_coordinate_topas, 209 | particles_per_history, 210 | sid_mm 211 | ); 212 | 213 | break; 214 | case rti::beam_id_type::STR: 215 | beam_source_ = rti_session_->get_beamsource( 216 | beam_id.name, 217 | rt_coordinate_topas, 218 | particles_per_history, 219 | sid_mm 220 | ); 221 | break; 222 | } 223 | 224 | /** 225 | * Set Beamlet range to be simulated. 226 | * By default, starts with first beamlet (id=1) and ends with last beamlets 227 | */ 228 | if(fPm->ParameterExists(GetFullParmName("beamletrange"))){ 229 | 230 | if( fPm->GetVectorLength(GetFullParmName("beamletrange")) != 2){ 231 | throw std::runtime_error("Beamlet start_id is lower than end_id."); 232 | } 233 | 234 | int* v = fPm->GetIntegerVector(GetFullParmName("beamletrange")); 235 | 236 | (v[0] <= 0) ? throw std::runtime_error("Beamlet range error. start id should be from 1") : false ; 237 | (v[0] >= v[1]) ? throw std::runtime_error("Beamlet range error. [start=1, stop=end]") : false ; 238 | 239 | //due to index start 0 in beam source 240 | counter_.start = v[0] - 1 ; 241 | counter_.stop = v[1] - 1 ; 242 | 243 | }else{ 244 | counter_.start = 0; 245 | counter_.stop = beam_source_.total_beamlets()-1; 246 | } 247 | 248 | counter_.current = counter_.start; 249 | fNumberOfHistoriesInRun = std::get<2>(beam_source_[counter_.stop]) 250 | - std::get<2>(beam_source_[counter_.start]) 251 | + std::get<1>(beam_source_[counter_.start]); 252 | std::cout<<"Total number of histories to be simulated from RTIonSource: " << fNumberOfHistoriesInRun 253 | <<", Total number of beamlets: "<< beam_source_.total_beamlets() << std::endl; 254 | 255 | } 256 | 257 | G4bool 258 | TsRTIonSource::ReadHistoriesPerBeamlet(std::queue* particleBuffer) 259 | { 260 | #ifdef TOPAS_MT 261 | G4AutoLock l(&move_to_nextspot); 262 | #endif 263 | 264 | if( counter_.current > counter_.stop) return false; 265 | 266 | auto current_beamlet = beam_source_[counter_.current++]; 267 | auto beamlet_distribution = std::get<0>(current_beamlet); 268 | size_t histories_of_beamlet = std::get<1>(current_beamlet); 269 | 270 | while(histories_of_beamlet--){ 271 | 272 | auto h = beamlet_distribution(); 273 | TsPrimaryParticle p; 274 | p.particleDefinition = particle_definition_; 275 | 276 | p.posX = h.pos.x; 277 | p.posY = h.pos.y; 278 | p.posZ = h.pos.z; 279 | 280 | p.dCos1 = h.dir.x ; 281 | p.dCos2 = h.dir.y ; 282 | p.dCos3 = h.dir.z ; 283 | p.kEnergy = h.ke; 284 | p.weight = 1; 285 | p.isNewHistory = true; 286 | p.isOpticalPhoton = false; 287 | p.isGenericIon = false; 288 | p.ionCharge = 1 ; 289 | 290 | particleBuffer->push(p); 291 | } 292 | 293 | return true; 294 | } 295 | 296 | 297 | void 298 | TsRTIonSource::ExportDICOMCoordinateToParameters( rti::coordinate_transform& p) 299 | { 300 | //1. isocenter 301 | this->Wrap3Vector(p.translation, "IsoCenter"); 302 | 303 | //Angle 0. beam limiting devide pitch angle 304 | this->Wrap1Vector(p.collimator.z, "CollimatorAngle"); 305 | 306 | //Angle 1. gantry angle 307 | this->Wrap1Vector(p.gantry.y , "GantryAngle"); 308 | 309 | //Angle 2. patient support angle 310 | this->Wrap1Vector(p.patient_support.z, "PatientSupportAngle"); 311 | 312 | //Angle 3. IEC2DICOM angle 313 | this->Wrap1Vector(p.iec2dicom.x, "Iec2DicomAngle"); 314 | 315 | } 316 | 317 | void 318 | TsRTIonSource::Wrap3Vector( rti::vec3 vec, 319 | const char* name, 320 | const char* unit) 321 | { 322 | G4String param_name; 323 | G4String trans_value; 324 | 325 | param_name = "dc:So/" + fSourceName + "/" + name + "X"; 326 | trans_value = G4UIcommand::ConvertToString(vec.x) + " " + unit; 327 | fPm->AddParameter(param_name, trans_value); 328 | 329 | param_name = "dc:So/" + fSourceName + "/" + name + "Y"; 330 | trans_value = G4UIcommand::ConvertToString(vec.y)+ " " + unit; 331 | fPm->AddParameter(param_name, trans_value); 332 | 333 | param_name = "dc:So/" + fSourceName + "/" + name + "Z"; 334 | trans_value = G4UIcommand::ConvertToString(vec.z) + " " + unit; 335 | fPm->AddParameter(param_name, trans_value); 336 | } 337 | 338 | void 339 | TsRTIonSource::Wrap1Vector( float value, 340 | const char* name, 341 | const char* unit) 342 | { 343 | G4String param_name; 344 | G4String trans_value; 345 | 346 | param_name = "dc:So/" + fSourceName + "/" + name ; 347 | trans_value = G4UIcommand::ConvertToString(value) + " " + unit; 348 | fPm->AddParameter(param_name, trans_value); 349 | } 350 | -------------------------------------------------------------------------------- /rti/test/session/hist.txt: -------------------------------------------------------------------------------- 1 | 84.6012 -79.3779 -65.3812 -0.895831 -0.00794268 0.444324 155.03 2 | 85.4319 -66.4443 -63.7238 -0.895855 0.00304646 0.444336 155.03 3 | 80.4665 -53.1143 -73.6308 -0.897276 0.00854094 0.441388 155.03 4 | 84.9652 -87.5768 -64.655 -0.894318 -0.0135782 0.447226 152.34 5 | 85.5189 -82.2082 -63.5503 -0.89585 -0.00802766 0.444285 152.34 6 | 77.3443 -69.7483 -79.8603 -0.898776 -0.00802726 0.438334 152.34 7 | 77.8096 -73.3678 -78.9319 -0.897344 -0.00247642 0.441324 152.34 8 | 87.6005 -76.2036 -59.3971 -0.894398 -0.00247649 0.447266 152.34 9 | 90.4268 -70.9392 -53.758 -0.892908 0.00307498 0.450229 152.34 10 | 77.7289 -69.3508 -79.0929 -0.895874 0.00307496 0.444297 152.34 11 | 79.4459 -59.738 -75.6671 -0.898801 0.0030748 0.438346 152.34 12 | 75.6951 -51.8435 -83.1507 -0.901688 0.00307451 0.432376 152.34 13 | 75.7666 -52.2047 -83.008 -0.90022 0.00862531 0.435349 152.34 14 | 75.9477 -59.6432 -82.6467 -0.897314 0.00862593 0.441309 152.34 15 | 88.4776 -56.7808 -57.6472 -0.894367 0.00862618 0.447251 152.34 16 | 91.9065 -84.062 -50.8058 -0.891287 -0.013735 0.453232 149.53 17 | 79.6924 -90.156 -75.1753 -0.894316 -0.0137352 0.447225 149.53 18 | 77.1742 -85.7647 -80.1996 -0.900253 -0.0137338 0.435151 149.53 19 | 69.1613 -77.7444 -96.187 -0.901766 -0.00812045 0.432148 149.53 20 | 77.5937 -84.6151 -79.3627 -0.898839 -0.00812124 0.438204 149.53 21 | 85.5753 -91.8468 -63.4377 -0.895871 -0.00812165 0.444241 149.53 22 | 89.8035 -83.6864 -55.0017 -0.892861 -0.0081217 0.450259 149.53 23 | 88.7835 -81.8228 -57.0367 -0.889812 -0.00812139 0.456256 149.53 24 | 95.9523 -68.4224 -42.7336 -0.888299 -0.0025078 0.45926 149.53 25 | 93.4017 -86.1539 -47.8225 -0.891368 -0.00250795 0.453274 149.53 26 | 87.037 -71.8704 -60.5213 -0.894397 -0.00250799 0.447266 149.53 27 | 75.183 -65.4695 -84.1725 -0.897386 -0.00250792 0.441238 149.53 28 | 75.8141 -63.2212 -82.9133 -0.900335 -0.00250773 0.435191 149.53 29 | 75.6265 -61.3954 -83.2875 -0.901792 0.003106 0.43216 149.53 30 | 75.2611 -45.6103 -84.0166 -0.898864 0.0031063 0.438217 149.53 31 | 83.8148 -70.8989 -66.9504 -0.895896 0.00310646 0.444254 149.53 32 | 89.2768 -78.7026 -56.0526 -0.892886 0.00310648 0.450271 149.53 33 | 94.2353 -45.1865 -46.1594 -0.889837 0.00310636 0.456268 149.53 34 | 92.0162 -76.0675 -50.5869 -0.891337 0.00872003 0.453258 149.53 35 | 88.3683 -57.2763 -57.8651 -0.894366 0.00872018 0.44725 149.53 36 | 80.784 -55.0746 -72.9974 -0.897355 0.00871993 0.441223 149.53 37 | 70.3595 -43.532 -93.7962 -0.900303 0.00871928 0.435176 149.53 38 | 75.4034 -42.3006 -83.7327 -0.901703 0.0143313 0.432118 149.53 39 | 77.8259 -55.4448 -78.8993 -0.898776 0.0143327 0.438174 149.53 40 | 78.873 -43.3811 -76.8101 -0.895808 0.0143334 0.44421 149.53 41 | 89.8583 -31.0256 -54.8923 -0.892799 0.0143335 0.450227 149.53 42 | 93.2721 -81.5535 -48.0811 -0.891238 -0.0139039 0.453323 146.68 43 | 85.007 -95.7496 -64.5715 -0.894314 -0.0139041 0.447224 146.68 44 | 77.0086 -96.7501 -80.53 -0.897348 -0.0139037 0.441105 146.68 45 | 77.047 -102.312 -80.4535 -0.90034 -0.0139027 0.434965 146.68 46 | 74.9201 -80.3844 -84.697 -0.901877 -0.0082219 0.431916 146.68 47 | 73.4922 -88.2496 -87.546 -0.898906 -0.00822272 0.438065 146.68 48 | 85.0135 -93.7612 -64.5587 -0.895892 -0.00822315 0.444195 146.68 49 | 90.3858 -76.7007 -53.8399 -0.892837 -0.0082232 0.450304 146.68 50 | 91.6381 -79.9941 -51.3412 -0.889741 -0.00822287 0.456392 146.68 51 | 96.7609 -74.561 -41.1203 -0.886603 -0.00822215 0.462458 146.68 52 | 98.1719 -73.666 -38.3051 -0.888204 -0.00254128 0.459442 146.68 53 | 92.8343 -82.8674 -48.9546 -0.891321 -0.00254145 0.453365 146.68 54 | 79.8554 -66.9117 -74.8502 -0.894397 -0.00254149 0.447266 146.68 55 | 81.0047 -73.1085 -72.5569 -0.897432 -0.00254141 0.441146 146.68 56 | 78.2146 -87.4794 -78.1238 -0.900424 -0.00254122 0.435006 146.68 57 | 70.9715 -79.9582 -92.5753 -0.903373 -0.00254091 0.428848 146.68 58 | 66.5768 -54.472 -101.344 -0.901903 0.00313948 0.431928 146.68 59 | 78.6958 -52.2428 -77.1638 -0.898932 0.00313979 0.438078 146.68 60 | 83.8782 -59.8929 -66.8237 -0.895918 0.00313996 0.444208 146.68 61 | 88.8929 -63.5486 -56.8185 -0.892863 0.00313998 0.450317 146.68 62 | 94.5628 -66.0067 -45.5059 -0.889766 0.00313985 0.456405 146.68 63 | 93.6271 -64.5211 -47.3728 -0.891289 0.0088215 0.453349 146.68 64 | 85.9586 -45.0684 -62.6729 -0.894365 0.00882166 0.44725 146.68 65 | 75.0829 -61.7378 -84.3723 -0.8974 0.0088214 0.44113 146.68 66 | 72.3207 -56.8729 -89.8834 -0.900392 0.00882072 0.43499 146.68 67 | 72.549 -52.5104 -89.4278 -0.903341 0.00881964 0.428832 146.68 68 | 74.0998 -50.3698 -86.3337 -0.901812 0.0145001 0.431885 146.68 69 | 72.9546 -45.671 -88.6186 -0.898842 0.0145016 0.438034 146.68 70 | 83.1045 -42.2474 -68.3676 -0.895829 0.0145023 0.444163 146.68 71 | 89.49 -46.9788 -55.6272 -0.892774 0.0145024 0.450272 146.68 72 | 82.5772 -102.177 -69.4196 -0.892714 -0.0169615 0.450304 143.79 73 | 96.4345 -93.1242 -41.7715 -0.889567 -0.0169608 0.456489 143.79 74 | 97.1805 -88.1221 -40.2831 -0.88805 -0.0112084 0.45961 143.79 75 | 84.8258 -90.9127 -64.9332 -0.891219 -0.0112091 0.453436 143.79 76 | 87.3103 -84.3103 -59.976 -0.894344 -0.0112093 0.447239 143.79 77 | 82.6848 -87.9234 -69.2049 -0.897427 -0.011209 0.441021 143.79 78 | 74.0458 -90.1659 -86.4413 -0.900466 -0.0112081 0.434783 143.79 79 | 69.2587 -90.6604 -95.9926 -0.902012 -0.00545451 0.431676 143.79 80 | 80.19 -77.5165 -74.1825 -0.898995 -0.00545507 0.437925 143.79 81 | 86.6708 -67.2447 -61.2519 -0.892829 -0.0054554 0.450362 143.79 82 | 91.1788 -79.096 -52.2577 -0.889682 -0.00545518 0.456548 143.79 83 | 98.8476 -62.8843 -36.9568 -0.888106 0.000298975 0.459639 143.79 84 | 92.1709 -59.8112 -50.2783 -0.891275 0.000298995 0.453464 143.79 85 | 83.9319 -61.5321 -66.7166 -0.8944 0.000299 0.447267 143.79 86 | 77.8881 -75.4448 -78.7753 -0.900522 0.000298967 0.43481 143.79 87 | 70.775 -72.7178 -92.9674 -0.903518 0.00029893 0.428551 143.79 88 | 66.3901 -47.7074 -101.716 -0.902009 0.00605238 0.431675 143.79 89 | 78.3339 -51.6566 -77.8858 -0.898992 0.006053 0.437923 143.79 90 | 85.9374 -50.714 -62.7152 -0.895931 0.00605333 0.444153 143.79 91 | 88.9995 -64.7721 -56.6059 -0.892826 0.00605336 0.45036 143.79 92 | 90.2557 -53.6744 -54.0995 -0.889679 0.00605311 0.456546 143.79 93 | 98.021 -48.038 -38.6062 -0.888044 0.0118062 0.459607 143.79 94 | 93.1299 -56.3253 -48.3649 -0.891212 0.011807 0.453433 143.79 95 | 84.1135 -45.7062 -66.3543 -0.894338 0.0118072 0.447236 143.79 96 | 77.8184 -64.2958 -78.9143 -0.897421 0.0118068 0.441018 143.79 97 | 77.0384 -36.7199 -80.4706 -0.90046 0.0118059 0.43478 143.79 98 | 75.5194 -41.2057 -83.5014 -0.89887 0.0175587 0.437864 143.79 99 | 81.1583 -36.3879 -72.2505 -0.895809 0.0175596 0.444092 143.79 100 | 91.0676 -39.5589 -52.4796 -0.892705 0.0175597 0.450299 143.79 101 | 89.3211 -102.852 -55.9641 -0.892684 -0.0172004 0.450355 140.8 102 | 87.6053 -103.985 -59.3875 -0.889482 -0.0171996 0.456646 140.8 103 | 96.9101 -84.5259 -40.8225 -0.887939 -0.0113673 0.459821 140.8 104 | 93.3454 -87.9708 -47.9349 -0.891163 -0.011368 0.453541 140.8 105 | 84.6962 -94.6957 -65.1918 -0.894343 -0.0113683 0.447238 140.8 106 | 76.6905 -87.7303 -81.1648 -0.897478 -0.0113679 0.440913 140.8 107 | 76.6302 -87.0873 -81.2849 -0.900568 -0.011367 0.434567 140.8 108 | 74.4037 -103.292 -85.7274 -0.90214 -0.00553396 0.431407 140.8 109 | 88.9983 -82.2977 -56.6081 -0.8896 -0.00553465 0.456707 140.8 110 | 98.7801 -73.3437 -37.0916 -0.886354 -0.00553413 0.462975 140.8 111 | 98.9617 -80.9842 -36.7292 -0.887996 0.000298974 0.459851 140.8 112 | 88.8442 -69.2675 -56.9156 -0.89122 0.000298994 0.453571 140.8 113 | 85.7346 -59.1795 -63.12 -0.8944 0.000299 0.447267 140.8 114 | 77.6269 -65.2169 -79.2964 -0.900626 0.000298966 0.434595 140.8 115 | 70.5281 -69.4158 -93.4599 -0.903671 0.000298927 0.428228 140.8 116 | 70.7748 -58.4958 -92.9678 -0.902137 0.00613233 0.431406 140.8 117 | 87.0963 -54.8321 -60.403 -0.895957 0.00613332 0.444099 140.8 118 | 89.0749 -40.7481 -56.4553 -0.892799 0.00613336 0.450413 140.8 119 | 87.5007 -57.528 -59.5961 -0.889597 0.0061331 0.456705 140.8 120 | 99.8313 -61.1264 -34.9942 -0.886351 0.00613252 0.462973 140.8 121 | 98.6246 -31.9378 -37.4018 -0.887932 0.0119656 0.459818 140.8 122 | 89.5843 -46.1008 -55.4391 -0.891157 0.0119664 0.453538 140.8 123 | 82.7225 -52.4984 -69.1296 -0.894336 0.0119666 0.447235 140.8 124 | 83.0026 -52.3883 -68.5709 -0.897472 0.0119663 0.44091 140.8 125 | 74.9594 -49.017 -84.6186 -0.900562 0.0119653 0.434564 140.8 126 | 84.2052 -27.9541 -66.1714 -0.895832 0.0177985 0.444037 140.8 127 | 90.8898 -34.632 -52.8342 -0.892674 0.0177986 0.45035 140.8 128 | 82.4784 -116.579 -69.6167 -0.895869 -0.0174921 0.443974 137.36 129 | 86.7307 -97.6976 -61.1325 -0.892647 -0.0174923 0.450417 137.36 130 | 96.1743 -106.22 -42.2906 -0.889378 -0.0174915 0.456837 137.36 131 | 97.0653 -91.3178 -40.5129 -0.887804 -0.0115617 0.460077 137.36 132 | 79.3653 -100.215 -75.828 -0.894341 -0.0115627 0.447237 137.36 133 | 81.9251 -84.3173 -70.7206 -0.897539 -0.0115624 0.440782 137.36 134 | 76.7525 -91.7509 -81.0409 -0.900692 -0.0115614 0.434305 137.36 135 | 69.9159 -92.1985 -94.6813 -0.902296 -0.0056309 0.431081 137.36 136 | 80.3027 -81.2312 -73.9577 -0.895992 -0.00563185 0.444035 137.36 137 | 91.0153 -80.8493 -52.5839 -0.892769 -0.00563189 0.450479 137.36 138 | 100.422 -94.6521 -33.815 -0.886186 -0.00563109 0.463295 137.36 139 | 90.6976 -57.4216 -53.2177 -0.887863 0.000298973 0.460108 137.36 140 | 93.9866 -51.6659 -46.6554 -0.891155 0.000298994 0.4537 137.36 141 | 86.4321 -69.3107 -61.7282 -0.8944 0.000299 0.447267 137.36 142 | 75.8199 -65.8075 -82.9017 -0.8976 0.00029899 0.440812 137.36 143 | 76.2053 -51.9036 -82.1327 -0.900752 0.000298965 0.434334 137.36 144 | 74.1919 -57.2974 -86.1498 -0.902293 0.00622927 0.431079 137.36 145 | 89.5519 -52.1301 -55.5036 -0.889497 0.00623008 0.456898 137.36 146 | 98.5774 -44.2925 -37.4959 -0.886183 0.00622947 0.463294 137.36 147 | 99.0455 -45.78 -36.5619 -0.887797 0.01216 0.460074 137.36 148 | 92.4574 -53.8446 -49.7066 -0.891089 0.0121609 0.453666 137.36 149 | 79.7298 -36.8371 -75.1006 -0.894334 0.0121611 0.447234 137.36 150 | 81.1982 -45.6924 -72.1709 -0.897533 0.0121607 0.440779 137.36 151 | 77.296 -57.737 -79.9567 -0.900685 0.0121597 0.434302 137.36 152 | 82.6427 -41.5015 -69.2888 -0.895859 0.0180904 0.443969 137.36 153 | 86.3472 -33.8212 -61.8977 -0.892637 0.0180905 0.450413 137.36 154 | 96.3296 -29.7851 -41.9807 -0.889369 0.0180897 0.456832 137.36 155 | 87.6715 -93.2696 -59.2553 -0.892611 -0.0177716 0.450477 134.26 156 | 92.5361 -89.5349 -49.5495 -0.88928 -0.0177708 0.457018 134.26 157 | 99.0507 -87.9585 -36.5517 -0.887675 -0.0117481 0.46032 134.26 158 | 81.3445 -101.169 -71.879 -0.894339 -0.0117492 0.447236 134.26 159 | 79.098 -94.6595 -76.3613 -0.897598 -0.0117488 0.440658 134.26 160 | 77.3849 -94.5456 -79.7793 -0.900809 -0.0117478 0.434057 134.26 161 | 71.7989 -91.4502 -90.9243 -0.902443 -0.00572434 0.43077 134.26 162 | 71.1357 -75.5547 -92.2477 -0.899257 -0.005725 0.437383 134.26 163 | 83.8005 -77.3268 -66.9788 -0.896022 -0.00572534 0.443974 134.26 164 | 90.3823 -91.6651 -53.8469 -0.892738 -0.00572538 0.45054 134.26 165 | 97.041 -65.4774 -40.5613 -0.886026 -0.00572453 0.4636 134.26 166 | 96.7631 -76.2653 -41.1158 -0.887736 0.000298972 0.460352 134.26 167 | 86.4636 -69.4173 -61.6654 -0.8944 0.000299 0.447267 134.26 168 | 72.8411 -71.536 -88.845 -0.900871 0.000298964 0.434086 134.26 169 | 73.8491 -53.5684 -86.8339 -0.90244 0.0063222 0.430769 134.26 170 | 78.8191 -53.5892 -76.9177 -0.899254 0.00632292 0.437381 134.26 171 | 76.4269 -60.4667 -81.6906 -0.896018 0.00632331 0.443972 134.26 172 | 94.6452 -50.5985 -45.3414 -0.889403 0.00632305 0.457081 134.26 173 | 99.9694 -54.3705 -34.7185 -0.886023 0.00632241 0.463598 134.26 174 | 97.0117 -60.6155 -40.6198 -0.887669 0.0123459 0.460317 134.26 175 | 88.1208 -43.1683 -58.3589 -0.891024 0.0123468 0.453787 134.26 176 | 81.8614 -35.3516 -70.8477 -0.897592 0.0123466 0.440655 134.26 177 | 76.4223 -50.9337 -81.6999 -0.900803 0.0123456 0.434053 134.26 178 | 77.1473 -36.1582 -80.2534 -0.895885 0.0183697 0.443906 134.26 179 | 88.2888 -18.757 -58.0238 -0.892602 0.0183698 0.450472 134.26 180 | 96.7513 -36.1202 -41.1394 -0.88927 0.018369 0.457013 134.26 181 | 73.5122 -97.9962 -87.5061 -0.897662 -0.0119517 0.440524 131.06 182 | 85.7968 -85.8428 -62.9958 -0.894336 -0.0119522 0.447235 131.06 183 | 94.2737 -72.6084 -46.0828 -0.890961 -0.0119519 0.453922 131.06 184 | 95.8105 -99.6461 -43.0164 -0.887536 -0.011951 0.460583 131.06 185 | 95.6879 -78.2673 -43.2612 -0.885854 -0.00582598 0.463928 131.06 186 | 90.0426 -76.7916 -54.5246 -0.892704 -0.00582688 0.450607 131.06 187 | 78.423 -88.483 -77.708 -0.899354 -0.00582648 0.437182 131.06 188 | 66.3593 -84.8109 -101.778 -0.902603 -0.00582579 0.430435 131.06 189 | 73.4735 -62.5198 -87.5833 -0.901 0.000298962 0.433819 131.06 190 | 88.1183 -54.6318 -58.3639 -0.8944 0.000299 0.447267 131.06 191 | 96.829 -57.7227 -40.9844 -0.8876 0.00029897 0.460615 131.06 192 | 93.9992 -47.6982 -46.6303 -0.88585 0.00642434 0.463926 131.06 193 | 95.2488 -51.409 -44.1371 -0.8893 0.00642502 0.457279 131.06 194 | 84.5683 -73.7982 -65.447 -0.896051 0.00642529 0.443905 131.06 195 | 71.9022 -51.0655 -90.7184 -0.899351 0.00642489 0.437181 131.06 196 | 75.5159 -43.3554 -83.5082 -0.900929 0.0125489 0.433785 131.06 197 | 81.5177 -53.749 -71.5336 -0.897655 0.0125501 0.44052 131.06 198 | 81.5899 -42.3592 -71.3894 -0.89433 0.0125505 0.447232 131.06 199 | 91.7659 -47.7059 -51.0862 -0.890955 0.0125502 0.453918 131.06 200 | 98.4212 -56.6919 -37.8077 -0.88753 0.0125493 0.460579 131.06 201 | 87.7478 -33.0866 -59.1032 -0.889163 0.0186732 0.457208 131.06 202 | 89.2163 -19.884 -56.1733 -0.892563 0.0186742 0.450536 131.06 203 | 85.5538 -40.1591 -63.4807 -0.895913 0.018674 0.443837 131.06 204 | 83.1406 -99.7062 -68.2955 -0.894249 -0.0184039 0.447192 127.8 205 | 74.0035 -68.2559 -86.5257 -0.899406 -0.0121697 0.436944 127.8 206 | 84.5932 -95.8426 -65.3971 -0.896038 -0.0121705 0.44381 127.8 207 | 89.3838 -85.1239 -55.8391 -0.892617 -0.0121706 0.450651 127.8 208 | 87.9775 -74.7484 -58.6448 -0.889144 -0.0121699 0.457466 127.8 209 | 101.788 -111.171 -31.091 -0.88562 -0.0121686 0.464252 127.8 210 | 93.2443 -86.9789 -48.1366 -0.887438 -0.00593528 0.460888 127.8 211 | 84.0624 -83.0292 -66.4563 -0.894385 -0.0059359 0.447259 127.8 212 | 93.4892 -93.1743 -47.6478 -0.89778 -0.00593568 0.440405 127.8 213 | 77.098 -72.3566 -80.3517 -0.899473 0.000298977 0.436976 127.8 214 | 76.078 -69.0239 -82.3868 -0.896105 0.000298997 0.443843 127.8 215 | 101.841 -78.6503 -30.9847 -0.885685 0.000298951 0.464286 127.8 216 | 99.2858 -44.6392 -36.0826 -0.887435 0.00653368 0.460887 127.8 217 | 89.0686 -45.3516 -56.4679 -0.890934 0.00653421 0.454086 127.8 218 | 85.0803 -60.592 -64.4254 -0.894381 0.00653436 0.447258 127.8 219 | 82.4043 -56.4228 -69.7645 -0.897776 0.00653412 0.440403 127.8 220 | 83.5906 -49.4497 -67.3977 -0.896031 0.0127688 0.443807 127.8 221 | 82.9734 -46.3251 -68.629 -0.89261 0.0127689 0.450648 127.8 222 | 95.5294 -47.4367 -43.5774 -0.889137 0.0127682 0.457462 127.8 223 | 100.429 -38.853 -33.8014 -0.885613 0.0127668 0.464248 127.8 224 | 93.6633 -41.4593 -47.3006 -0.890792 0.0190016 0.454013 127.8 225 | 86.8495 -83.9803 -60.8954 -0.892576 -0.0124095 0.450727 124.41 226 | 93.341 -86.686 -47.9437 -0.889024 -0.0124088 0.457693 124.41 227 | 102.882 -98.0663 -28.9078 -0.885418 -0.0124074 0.464631 124.41 228 | 98.669 -86.1867 -37.3131 -0.887279 -0.00605473 0.461193 124.41 229 | 79.1247 -74.8883 -76.308 -0.894384 -0.00605538 0.447259 124.41 230 | 80.4687 -83.3982 -73.6264 -0.897854 -0.00605516 0.440251 124.41 231 | 85.2533 -72.2955 -64.0802 -0.896142 0.000298997 0.443766 124.41 232 | 97.3888 -64.6979 -39.8675 -0.885486 0.000298948 0.464666 124.41 233 | 94.972 -42.533 -44.6894 -0.887276 0.00665313 0.461191 124.41 234 | 93.545 -63.6402 -47.5365 -0.890855 0.00665369 0.454238 124.41 235 | 86.1937 -53.5475 -62.2039 -0.894381 0.00665385 0.447257 124.41 236 | 72.8837 -58.0999 -88.7601 -0.897851 0.00665359 0.440249 124.41 237 | 98.501 -47.9725 -37.6484 -0.892569 0.0130078 0.450723 124.41 238 | 94.7983 -58.9467 -45.036 -0.889017 0.0130071 0.45769 124.41 239 | 90.3275 -105.118 -53.9561 -0.888895 -0.0126652 0.457935 120.96 240 | 99.3055 -75.2039 -36.0433 -0.88711 -0.00618318 0.461516 120.96 241 | 92.8323 -86.6641 -48.9586 -0.890775 -0.00618373 0.454402 120.96 242 | 79.8427 -93.0846 -74.8754 -0.894383 -0.00618389 0.447259 120.96 243 | 90.3704 -60.9656 -53.8705 -0.892603 0.000298999 0.450843 120.96 244 | 95.6118 -45.1656 -43.4129 -0.888967 0.000298982 0.457972 120.96 245 | 94.3769 -71.3888 -45.8768 -0.885274 0.000298946 0.46507 120.96 246 | 91.2583 -60.9391 -52.0989 -0.890772 0.00678168 0.454401 120.96 247 | -------------------------------------------------------------------------------- /rti/base/rti_matrix.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTI_MATRIX_H 2 | #define RTI_MATRIX_H 3 | 4 | /// \file 5 | /// 6 | /// RT-Ion matrix 3x3 and 4x4 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace rti{ 16 | 17 | /// \class mat3x3 18 | /// 3x3 matrix 19 | /// \tparam T type of matrix elements 20 | template 21 | class mat3x3 { 22 | public: 23 | ///< angle in radian 24 | T x; 25 | T y; 26 | T z; 27 | //matrix element 28 | T xx; 29 | T xy; 30 | T xz; 31 | T yx; 32 | T yy; 33 | T yz; 34 | T zx; 35 | T zy; 36 | T zz; 37 | 38 | CUDA_HOST_DEVICE 39 | mat3x3(): 40 | x(0),y(0),z(0), 41 | xx(1.0),xy(0),xz(0), 42 | yx(0),yy(1.0),yz(0), 43 | zx(0),zy(0),zz(1.0) 44 | {;} 45 | 46 | CUDA_HOST_DEVICE 47 | mat3x3(T xx_, T xy_, T xz_,T yx_, T yy_, T yz_,T zx_, T zy_, T zz_ ): 48 | x(0),y(0),z(0), 49 | xx(xx_),xy(xy_),xz(xz_), 50 | yx(yx_),yy(yy_),yz(yz_), 51 | zx(zx_),zy(zy_),zz(zz_) 52 | {;} 53 | 54 | CUDA_HOST_DEVICE 55 | mat3x3(const mat3x3& ref) : 56 | x (ref.x ), 57 | y (ref.y ), 58 | z (ref.z ), 59 | xx(ref.xx), 60 | xy(ref.xy), 61 | xz(ref.xz), 62 | yx(ref.yx), 63 | yy(ref.yy), 64 | yz(ref.yz), 65 | zx(ref.zx), 66 | zy(ref.zy), 67 | zz(ref.zz) 68 | {;} 69 | 70 | CUDA_HOST_DEVICE 71 | mat3x3(T a, T b, T c): 72 | x(a),y(b),z(c), 73 | xx(1.0),xy(0),xz(0), 74 | yx(0),yy(1.0),yz(0), 75 | zx(0),zy(0),zz(1.0){ 76 | //this routine may need a sequence of rotation, 77 | //e.g., x->y->z, y->x->z, etc. a total of 12 78 | if (x != 0) this->rotate_x(x); 79 | if (y != 0) this->rotate_y(y); 80 | if (z != 0) this->rotate_z(z); 81 | } 82 | 83 | CUDA_HOST_DEVICE 84 | mat3x3(std::array& abc): 85 | x(abc[0]),y(abc[1]),z(abc[2]), 86 | xx(1.0),xy(0),xz(0), 87 | yx(0),yy(1.0),yz(0), 88 | zx(0),zy(0),zz(1.0) 89 | { 90 | if (x != 0) this->rotate_x(x); 91 | if (y != 0) this->rotate_y(y); 92 | if (z != 0) this->rotate_z(z); 93 | } 94 | 95 | /// Assignment operator 96 | CUDA_HOST_DEVICE 97 | mat3x3& 98 | operator=(const mat3x3& ref) 99 | { 100 | x = ref.x ; 101 | y = ref.y; 102 | z = ref.z; 103 | xx = ref.xx; 104 | xy = ref.xy; 105 | xz = ref.xz; 106 | yx = ref.yx; 107 | yy = ref.yy; 108 | yz = ref.yz; 109 | zx = ref.zx; 110 | zy = ref.zy; 111 | zz = ref.zz; 112 | return *this; 113 | } 114 | 115 | //Calculate rotation matrix from two vectors, from (f) and to (t). 116 | //the matrix rotates f and aligns t. 117 | // f and t are normalized one 118 | /* 119 | CUDA_HOST_DEVICE 120 | mat3x3 121 | (rti::vec3& f, 122 | rti::vec3& t) 123 | { 124 | f.normalize(); 125 | t.normalize(); 126 | printf("here\n"); 127 | rti::vec3 v = f.cross(t); 128 | rti::vec3 u = v / v.norm(); 129 | T c = f.dot(t); 130 | T h = 1-c/1-c*c; 131 | 132 | xx = c + h * v.x * v.x ; 133 | xy = h * v.x * v.y - v.z ; 134 | xz = h * v.x * v.z + v.y ; 135 | yx = h * v.x * v.y + v.z ; 136 | yy = c + h * v.y * v.y ; 137 | yz = h * v.y * v.z - v.x ; 138 | zx = h * v.x * v.z - v.y ; 139 | zy = h * v.y * v.z + v.x ; 140 | zz = c + h * v.z * v.z ; 141 | //calculat euler angle x->y->z sequence 142 | } 143 | */ 144 | 145 | //expecting normalized vectors, f and t 146 | CUDA_HOST_DEVICE 147 | mat3x3 148 | (const rti::vec3& f, 149 | const rti::vec3& t) 150 | { 151 | ///< a matrix aligns vector (f) to vector (t) 152 | ///< by Moller & Hughe, 1999 153 | rti::vec3 v = f.cross(t); 154 | T c = 1 ; 155 | T h = 0 ; 156 | if ( v.norm() <= 0.0001 ) { 157 | v.x = 0 ; 158 | v.y = 0 ; 159 | v.z = 0 ; 160 | }else{ 161 | v.normalize(); 162 | c = f.dot(t); 163 | h = (1.0-c)/(1.0-c*c); 164 | } 165 | 166 | xx = c + h * v.x * v.x ; 167 | xy = h * v.x * v.y - v.z ; 168 | xz = h * v.x * v.z + v.y ; 169 | yx = h * v.x * v.y + v.z ; 170 | yy = c + h * v.y * v.y ; 171 | yz = h * v.y * v.z - v.x ; 172 | zx = h * v.x * v.z - v.y ; 173 | zy = h * v.y * v.z + v.x ; 174 | zz = c + h * v.z * v.z ; 175 | 176 | } 177 | 178 | CUDA_HOST_DEVICE 179 | ~mat3x3(){;} 180 | 181 | 182 | CUDA_HOST 183 | rti::vec3 184 | euler_xyz(bool y_is_2nd_quad=false){ 185 | //R_z(phi)*R_y(theta)*R_x(psi) 186 | //psi_th_phi.x = psi 187 | //psi_th_phi.y = th 188 | //psi_th_phi.z = phi 189 | rti::vec3 psi_th_phi; 190 | 191 | if( zx > -1.0 && zx < 1.0 ){ //zx neq -1 or 1 192 | T psi[2], th[2], phi[2]; 193 | th[0] = -1.0 * std::asin(zx); 194 | th[1] = M_PI - th[0]; 195 | psi[0] = std::atan2(zy/std::cos(th[0]), zz/std::cos(th[0])); 196 | psi[1] = std::atan2(zy/std::cos(th[1]), zz/std::cos(th[1])); 197 | phi[0] = std::atan2(yx/std::cos(th[0]), xx/std::cos(th[0])); 198 | phi[1] = std::atan2(yx/std::cos(th[1]), xx/std::cos(th[1])); 199 | 200 | if ( th[0] > 0 && th[0] < M_PI*0.5 ){ 201 | psi_th_phi.x = psi[0]; 202 | psi_th_phi.y = th[0]; 203 | psi_th_phi.z = phi[0]; 204 | }else{ 205 | psi_th_phi.x = psi[1]; 206 | psi_th_phi.y = th[1]; 207 | psi_th_phi.z = phi[1]; 208 | } 209 | // 210 | //psi_th_phi.x = psi[y_is_2nd_quad]; 211 | //psi_th_phi.y = th[y_is_2nd_quad]; 212 | //psi_th_phi.z = phi[y_is_2nd_quad]; 213 | }else{ 214 | std::cout<<"here\n";//never get here 215 | psi_th_phi.z = 0.0 ; 216 | if ( zx == -1.0 ){//zx = -1 217 | psi_th_phi.x = psi_th_phi.z + std::atan2(xy, xz); 218 | psi_th_phi.y = M_PI * 0.5 ; 219 | }else{ 220 | psi_th_phi.x = -1.0 * psi_th_phi.z + std::atan2(-1.0*xy, -1.0*xz); 221 | psi_th_phi.y = -1.0 * M_PI * 0.5 ; 222 | } 223 | } 224 | 225 | #if defined(__CUDACC__) 226 | 227 | #else 228 | 229 | #endif 230 | return psi_th_phi; 231 | } 232 | 233 | CUDA_HOST_DEVICE 234 | mat3x3& 235 | rotate_x(T a){ 236 | x = a; 237 | #if defined(__CUDACC__) 238 | T c1 = cosf(x); 239 | T s1 = sinf(x); 240 | #else 241 | T c1 = std::cos(x); 242 | T s1 = std::sin(x); 243 | #endif 244 | T x1 = yx, y1 = yy, z1 = yz; 245 | yx = c1*x1 - s1*zx; 246 | yy = c1*y1 - s1*zy; 247 | yz = c1*z1 - s1*zz; 248 | zx = s1*x1 + c1*zx; 249 | zy = s1*y1 + c1*zy; 250 | zz = s1*z1 + c1*zz; 251 | return *this; 252 | } 253 | 254 | CUDA_HOST_DEVICE 255 | mat3x3& 256 | rotate_y(T a){ 257 | y = a; 258 | #if defined(__CUDACC__) 259 | T c1 = cosf(y); 260 | T s1 = sinf(y); 261 | #else 262 | T c1 = std::cos(y); 263 | T s1 = std::sin(y); 264 | #endif 265 | T x1 = zx, y1 = zy, z1 = zz; 266 | zx = c1*x1 - s1*xx; 267 | zy = c1*y1 - s1*xy; 268 | zz = c1*z1 - s1*xz; 269 | xx = s1*x1 + c1*xx; 270 | xy = s1*y1 + c1*xy; 271 | xz = s1*z1 + c1*xz; 272 | return *this; 273 | } 274 | 275 | CUDA_HOST_DEVICE 276 | mat3x3& 277 | rotate_z(T a){ 278 | z = a; 279 | #if defined(__CUDACC__) 280 | T c1 = cosf(z); 281 | T s1 = sinf(z); 282 | #else 283 | T c1 = std::cos(z); 284 | T s1 = std::sin(z); 285 | #endif 286 | T x1 = xx, y1 = xy, z1 = xz; 287 | xx = c1*x1 - s1*yx; 288 | xy = c1*y1 - s1*yy; 289 | xz = c1*z1 - s1*yz; 290 | yx = s1*x1 + c1*yx; 291 | yy = s1*y1 + c1*yy; 292 | yz = s1*z1 + c1*yz; 293 | return *this; 294 | } 295 | 296 | CUDA_HOST_DEVICE 297 | std::array 298 | operator * (const std::array& r) const { 299 | return std::array({ 300 | xx * r[0] + xy * r[1] + xz * r[2], 301 | yx * r[0] + yy * r[1] + yz * r[2], 302 | zx * r[0] + zy * r[1] + zz * r[2]}); 303 | } 304 | 305 | CUDA_HOST_DEVICE 306 | rti::vec3 307 | operator * (const rti::vec3& r) const { 308 | return rti::vec3( 309 | xx * r.x + xy * r.y + xz * r.z, 310 | yx * r.x + yy * r.y + yz * r.z, 311 | zx * r.x + zy * r.y + zz * r.z); 312 | } 313 | 314 | CUDA_HOST_DEVICE 315 | mat3x3 inverse() const { 316 | return rti::mat3x3(xx, yx, zx, xy, yy, zy, xz, yz, zz ); 317 | } 318 | 319 | /* 320 | mat3x3 321 | operator* (const mat3x3& r){ 322 | return mat3x3( 323 | xx*r.xx + xy*r.yx + xz*r.zx, 324 | xx*r.xy + xy*r.yy + xz*r.zy, 325 | xx*r.xz + xy*r.yz + xz*r.zz, 326 | yx*r.xx + yy*r.yx + yz*r.zx, 327 | yx*r.xy + yy*r.yy + yz*r.zy, 328 | yx*r.xz + yy*r.yz + yz*r.zz, 329 | zx*r.xx + zy*r.yx + zz*r.zx, 330 | zx*r.xy + zy*r.yy + zz*r.zy, 331 | zx*r.xz + zy*r.yz + zz*r.zz ); 332 | }*/ 333 | 334 | CUDA_HOST_DEVICE 335 | mat3x3 336 | operator* (const mat3x3& r) const { 337 | return mat3x3( 338 | xx*r.xx + xy*r.yx + xz*r.zx, 339 | xx*r.xy + xy*r.yy + xz*r.zy, 340 | xx*r.xz + xy*r.yz + xz*r.zz, 341 | yx*r.xx + yy*r.yx + yz*r.zx, 342 | yx*r.xy + yy*r.yy + yz*r.zy, 343 | yx*r.xz + yy*r.yz + yz*r.zz, 344 | zx*r.xx + zy*r.yx + zz*r.zx, 345 | zx*r.xy + zy*r.yy + zz*r.zy, 346 | zx*r.xz + zy*r.yz + zz*r.zz ); 347 | } 348 | 349 | CUDA_HOST_DEVICE 350 | void dump() const { 351 | #if defined(__CUDACC__) 352 | printf("xx,xy,xz %f, %f, %f\n", xx,xy, xz); 353 | printf("yx,yy,yz %f, %f, %f\n", yx,yy, yz); 354 | printf("zx,zy,zz %f, %f, %f\n", zx,zy, zz); 355 | #else 356 | std::cout<<"xx,xy,xz "<< xx <<" " << xy <<" " << xz << std::endl; 357 | std::cout<<"yx,yy,yz "<< yx <<" " << yy <<" " << yz << std::endl; 358 | std::cout<<"zx,zy,zz "<< zx <<" " << zy <<" " << zz << std::endl; 359 | #endif 360 | } 361 | }; 362 | 363 | /// \class mat4x4 364 | /// 4x4 matrix 365 | /// \tparam T type of matrix elements 366 | template 367 | class mat4x4 { 368 | public: 369 | //matrix elements 370 | T xx; 371 | T xy; 372 | T xz; 373 | T xs; 374 | T yx; 375 | T yy; 376 | T yz; 377 | T ys; 378 | T zx; 379 | T zy; 380 | T zz; 381 | T zs; 382 | T sx; 383 | T sy; 384 | T sz; 385 | T ss; 386 | 387 | CUDA_HOST_DEVICE 388 | mat4x4(): 389 | xx(1.0),xy(0),xz(0),xs(0), 390 | yx(0),yy(1.0),yz(0),ys(0), 391 | zx(0),zy(0),zz(1.0),zs(0), 392 | sx(0),sy(0),sz(0.0),ss(1.0) 393 | {;} 394 | 395 | CUDA_HOST_DEVICE 396 | mat4x4( 397 | T xx_, T xy_, T xz_, T xs_, 398 | T yx_, T yy_, T yz_, T ys_, 399 | T zx_, T zy_, T zz_, T zs_, 400 | T sx_, T sy_, T sz_, T ss_ 401 | ): 402 | xx(xx_),xy(xy_),xz(xz_),xs(xs_), 403 | yx(yx_),yy(yy_),yz(yz_),ys(ys_), 404 | zx(zx_),zy(zy_),zz(zz_),zs(zs_), 405 | sx(sx_),sy(sy_),sz(sz_),ss(ss_) 406 | {;} 407 | 408 | CUDA_HOST_DEVICE 409 | mat4x4(const mat4x4& ref) 410 | { 411 | xx = ref.xx; 412 | xy = ref.xy; 413 | xz = ref.xz; 414 | xs = ref.xs; 415 | 416 | yx = ref.yx; 417 | yy = ref.yy; 418 | yz = ref.yz; 419 | ys = ref.ys; 420 | 421 | zx = ref.zx; 422 | zy = ref.zy; 423 | zz = ref.zz; 424 | zs = ref.zs; 425 | 426 | sx = ref.sx; 427 | sy = ref.sy; 428 | sz = ref.sz; 429 | ss = ref.ss; 430 | } 431 | 432 | CUDA_HOST_DEVICE 433 | mat4x4(const T* a) 434 | { 435 | xx = a[0]; xy = a[1]; xz = a[2]; xs = a[3]; 436 | yx = a[4]; yy = a[5]; yz = a[6]; ys = a[7]; 437 | zx = a[8]; zy = a[9]; zz = a[10]; zs = a[11]; 438 | sx = a[12]; sy = a[13]; sz = a[14];ss = a[15]; 439 | } 440 | 441 | CUDA_HOST_DEVICE 442 | mat4x4( 443 | const mat3x3& rot, 444 | const vec3& tra) 445 | { 446 | xx = rot.xx; 447 | xy = rot.xy; 448 | xz = rot.xz; 449 | xs = tra.x; 450 | 451 | yx = rot.yx; 452 | yy = rot.yy; 453 | yz = rot.yz; 454 | ys = tra.y; 455 | 456 | zx = rot.zx; 457 | zy = rot.zy; 458 | zz = rot.zz; 459 | zs = tra.z; 460 | 461 | sx = 0.0; 462 | sy = 0.0; 463 | sz = 0.0; 464 | ss = 1.0; 465 | } 466 | 467 | CUDA_HOST_DEVICE 468 | mat4x4(const mat3x3& rot) 469 | { 470 | xx = rot.xx; 471 | xy = rot.xy; 472 | xz = rot.xz; 473 | xs = 0.0; 474 | 475 | yx = rot.yx; 476 | yy = rot.yy; 477 | yz = rot.yz; 478 | ys = 0.0; 479 | 480 | zx = rot.zx; 481 | zy = rot.zy; 482 | zz = rot.zz; 483 | zs = 0.0; 484 | 485 | sx = 0.0; 486 | sy = 0.0; 487 | sz = 0.0; 488 | ss = 1.0; 489 | } 490 | 491 | CUDA_HOST_DEVICE 492 | mat4x4(const vec3& ref) 493 | { 494 | xx = 1.0; 495 | xy = 0.0; 496 | xz = 0.0; 497 | xs = ref.x; 498 | 499 | yx = 0.0; 500 | yy = 1.0; 501 | yz = 0.0; 502 | ys = ref.y; 503 | 504 | zx = 0.0; 505 | zy = 0.0; 506 | zz = 1.0; 507 | zs = ref.z; 508 | 509 | sx = 0.0; 510 | sy = 0.0; 511 | sz = 0.0; 512 | ss = 1.0; 513 | } 514 | 515 | 516 | CUDA_HOST_DEVICE 517 | ~mat4x4(){;} 518 | 519 | CUDA_HOST_DEVICE 520 | std::array 521 | operator * (const std::array& r) const 522 | { 523 | return std::array({ 524 | xx * r[0] + xy * r[1] + xz * r[2] + xs*r[3], 525 | yx * r[0] + yy * r[1] + yz * r[2] + ys*r[3], 526 | zx * r[0] + zy * r[1] + zz * r[2] + zs*r[3], 527 | sx * r[0] + sy * r[1] + sz * r[2] + ss*r[3]}); 528 | } 529 | 530 | CUDA_HOST_DEVICE 531 | rti::vec4 532 | operator * (const rti::vec4& r) const 533 | { 534 | return rti::vec4( 535 | xx * r.x + xy * r.y + xz * r.z + xs * r.s, 536 | yx * r.x + yy * r.y + yz * r.z + ys * r.s, 537 | zx * r.x + zy * r.y + zz * r.z + zs * r.s, 538 | sx * r.x + sy * r.y + sz * r.z + ss * r.s); 539 | } 540 | 541 | CUDA_HOST_DEVICE 542 | rti::vec3 543 | operator * (const rti::vec3& r) const 544 | { 545 | return rti::vec3( 546 | xx * r.x + xy * r.y + xz * r.z + xs , 547 | yx * r.x + yy * r.y + yz * r.z + ys , 548 | zx * r.x + zy * r.y + zz * r.z + zs ); 549 | } 550 | 551 | /* 552 | mat4x4 553 | operator* (const mat3x3& r){ 554 | return mat3x3( 555 | xx*r.xx + xy*r.yx + xz*r.zx, 556 | xx*r.xy + xy*r.yy + xz*r.zy, 557 | xx*r.xz + xy*r.yz + xz*r.zz, 558 | yx*r.xx + yy*r.yx + yz*r.zx, 559 | yx*r.xy + yy*r.yy + yz*r.zy, 560 | yx*r.xz + yy*r.yz + yz*r.zz, 561 | zx*r.xx + zy*r.yx + zz*r.zx, 562 | zx*r.xy + zy*r.yy + zz*r.zy, 563 | zx*r.xz + zy*r.yz + zz*r.zz ); 564 | }*/ 565 | 566 | CUDA_HOST_DEVICE 567 | mat4x4 568 | operator* (const mat4x4& r) const 569 | { 570 | return mat4x4( 571 | xx*r.xx + xy*r.yx + xz*r.zx + xs*r.sx, 572 | xx*r.xy + xy*r.yy + xz*r.zy + xs*r.sy, 573 | xx*r.xz + xy*r.yz + xz*r.zz + xs*r.sz, 574 | xx*r.xs + xy*r.ys + xz*r.zs + xs*r.ss, 575 | 576 | yx*r.xx + yy*r.yx + yz*r.zx + ys*r.sx, 577 | yx*r.xy + yy*r.yy + yz*r.zy + ys*r.sy, 578 | yx*r.xz + yy*r.yz + yz*r.zz + ys*r.sz, 579 | yx*r.xs + yy*r.ys + yz*r.zs + ys*r.ss, 580 | 581 | zx*r.xx + zy*r.yx + zz*r.zx + zs*r.sx, 582 | zx*r.xy + zy*r.yy + zz*r.zy + zs*r.sy, 583 | zx*r.xz + zy*r.yz + zz*r.zz + zs*r.sz, 584 | zx*r.xs + zy*r.ys + zz*r.zs + zs*r.ss, 585 | 586 | sx*r.xx + sy*r.yx + sz*r.zx + ss*r.sx, 587 | sx*r.xy + sy*r.yy + sz*r.zy + ss*r.sy, 588 | sx*r.xz + sy*r.yz + sz*r.zz + ss*r.sz, 589 | sx*r.xs + sy*r.ys + sz*r.zs + ss*r.ss 590 | ); 591 | } 592 | 593 | /* 594 | CUDA_HOST_DEVICE 595 | mat4x4 inverse() const { 596 | T det = xx*(yy*zz*ss + yx*zs*sy + ) 597 | //return rti::mat3x3(xx, yx, zx, xy, yy, zy, xz, yz, zz ); 598 | } 599 | */ 600 | 601 | CUDA_HOST_DEVICE 602 | void dump() const 603 | { 604 | #if defined(__CUDACC__) 605 | printf("xx,xy,xz,xs %f, %f, %f, %f\n", xx,xy, xz, xs); 606 | printf("yx,yy,yz,ys %f, %f, %f, %f\n", yx,yy, yz, ys); 607 | printf("zx,zy,zz,zs %f, %f, %f, %f\n", zx,zy, zz, zs); 608 | printf("sx,sy,sz,ss %f, %f, %f, %f\n", sx,sy, sz, ss); 609 | #else 610 | std::cout<<"xx,xy,xz,xs "<< xx <<" " << xy <<" " << xz << " " << xs << std::endl; 611 | std::cout<<"yx,yy,yz,ys "<< yx <<" " << yy <<" " << yz << " " << ys << std::endl; 612 | std::cout<<"zx,zy,zz,zs "<< zx <<" " << zy <<" " << zz << " " << zs << std::endl; 613 | std::cout<<"zx,zy,zz,ss "<< sx <<" " << sy <<" " << sz << " " << ss << std::endl; 614 | #endif 615 | } 616 | }; 617 | 618 | 619 | 620 | } 621 | #endif 622 | --------------------------------------------------------------------------------