5
5
from DoseEngines import AbstractScriptedDoseEngine
6
6
from DoseEngines import OrthovoltageDoseEngineUtil
7
7
from DoseEngines import EGSnrcUtil
8
+ from SegmentEditorEffects import SegmentEditorMaskVolumeEffect
8
9
9
10
#------------------------------------------------------------------------------
10
11
#
@@ -223,14 +224,16 @@ def defineBeamParameters(self):
223
224
"Z in the BEAMnrc run where the phase space source was scored (cm).\n \
224
225
Only needed if DBS is enabled." , 20 )
225
226
227
+ self .scriptedEngine .addBeamParameterLineEdit (
228
+ "Orthovoltage dose" , "EraseOutsideSegment" , "Erase outside segment:" ,
229
+ "If specified, causes the dose volume to be erased outside of the segment with the specified name." , "" )
230
+
226
231
#------------------------------------------------------------------------------
227
232
#TODO: Add a path parameter type using the CTK path selector that saves the selections to Application Settings
228
233
def savePathsInApplicationSettings (self , beamNode ):
229
234
if beamNode is None :
230
235
return
231
236
232
- settings = qt .QSettings ()
233
-
234
237
ctcreateExecFilePath = self .scriptedEngine .parameter (beamNode , "CtcreateExecFilePath" )
235
238
if ctcreateExecFilePath != self .ctcreateExecFilePathDefault :
236
239
qt .QSettings ().setValue ('OrthovoltageDoseEngine/CtcreateExecFilePath' , ctcreateExecFilePath )
@@ -284,7 +287,6 @@ def calculateDoseUsingEngine(self, beamNode, resultDoseVolumeNode):
284
287
ctcreateExecFilePath = self .scriptedEngine .parameter (beamNode , "CtcreateExecFilePath" )
285
288
ctcreateOutputPath = self .scriptedEngine .parameter (beamNode , "CtcreateOutputPath" )
286
289
roiNodeName = self .scriptedEngine .parameter (beamNode , "ROIName" )
287
- volumeName = self .scriptedEngine .parameter (beamNode , "VolumeName" )
288
290
sliceThicknessX = self .scriptedEngine .parameter (beamNode , "SliceThicknessX" )
289
291
sliceThicknessY = self .scriptedEngine .parameter (beamNode , "SliceThicknessY" )
290
292
sliceThicknessZ = self .scriptedEngine .parameter (beamNode , "SliceThicknessZ" )
@@ -305,15 +307,15 @@ def calculateDoseUsingEngine(self, beamNode, resultDoseVolumeNode):
305
307
##########################################
306
308
307
309
runCTCreateDOSXYZnrc = int (self .scriptedEngine .parameter (beamNode , "RunCTCreateDOSXYZnrc" ))
308
- if runCTCreateDOSXYZnrc != self .runCTCreateAndDoseXYZnrcIndex :
310
+ if runCTCreateDOSXYZnrc != self .runDOSXYZnrcOnlyIndex :
311
+ logging .info ("Running ctCreate" )
309
312
materialJSON = self .scriptedEngine .parameter (beamNode , "Materials" )
310
313
try :
311
314
materials = json .loads (materialJSON )
312
315
except :
313
316
logging .error ("Unable parse materials JSON string" )
314
317
315
318
lowerBound = self .scriptedEngine .parameter (beamNode , "LowerBound" )
316
-
317
319
OrthovoltageDoseEngineUtil .generateCtcreateInput (volumeNode , seriesUID , ctcreateOutputPath , materials , lowerBound , roiNode , thicknesses )
318
320
EGSnrcUtil .callCtcreate (ctcreateExecFilePath , ctcreateOutputPath )
319
321
@@ -409,7 +411,7 @@ def calculateDoseUsingEngine(self, beamNode, resultDoseVolumeNode):
409
411
410
412
ctcreateFilePath = ctcreateOutputPath
411
413
if runCTCreateDOSXYZnrc == self .runDOSXYZnrcOnlyIndex :
412
- ctcreateFilePath = self .scriptedEngine .parameter (beamNode , "ExistingCtcreatePath" )
414
+ ctcreateFilePath = self .scriptedEngine .parameter (beamNode , "ExistingCtcreatePath" )
413
415
414
416
if ctcreateFilePath == "" :
415
417
logging .error ("ctcreate file path not specified" )
@@ -504,5 +506,22 @@ def calculateDoseUsingEngine(self, beamNode, resultDoseVolumeNode):
504
506
logging .info ( 'Result dose volume for beam ' + beamNode .GetName () + ' successfully loaded.\n '
505
507
+ ' Dose range: ({:.4f}-{:.4f})' .format (accumulate .GetMin ()[0 ],accumulate .GetMax ()[0 ]) )
506
508
509
+ # Erase dose outside of the specified segment
510
+ maskSegmentId = ""
511
+ maskSegmentName = self .scriptedEngine .parameter (beamNode , "EraseOutsideSegment" )
512
+ segmentationNode = parentPlan .GetSegmentationNode ()
513
+ if segmentationNode is None or segmentationNode .GetSegmentation () is None :
514
+ logging .error ("Could not mask dose volume. Invalid segmentation." )
515
+ elif maskSegmentName != "" :
516
+ maskSegmentId = segmentationNode .GetSegmentation ().GetSegmentIdBySegmentName (maskSegmentName )
517
+
518
+ if maskSegmentId != "" :
519
+ logging .info (f"Erasing dose outside of { maskSegmentName } [ID: { maskSegmentId } ]" )
520
+ operationMode = "FILL_OUTSIDE"
521
+ fillValues = [0 ]
522
+ SegmentEditorMaskVolumeEffect .maskVolumeWithSegment (segmentationNode , maskSegmentId , operationMode , fillValues , resultDoseVolumeNode , resultDoseVolumeNode )
523
+ else :
524
+ logging .error ("Could not mask dose volume. Invalid segment id." )
525
+
507
526
# Successful execution, no error message
508
527
return ""
0 commit comments