@@ -279,6 +279,7 @@ def get_dvh_table(self, my_plan: Plan, constraint_list: list = None, opt_params:
279279 df .at [count , 'dose_gy' ] = self .dose_to_gy (dose_key , dvh_updated_list [i ]['parameters' ][dose_key ])
280280 df .at [count , 'volume_perc' ] = dvh_updated_list [i ]['constraints' ][limit_key ]
281281 df .at [count , 'dvh_type' ] = 'constraint'
282+ df .at [count , 'bound_type' ] = dvh_updated_list [i ]['constraints' ].get ('bound_type' , 'upper' )
282283 count = count + 1
283284 goal_key = self .matching_keys (dvh_updated_list [i ]['constraints' ], 'goal' )
284285 if goal_key in dvh_updated_list [i ]['constraints' ]:
@@ -287,6 +288,7 @@ def get_dvh_table(self, my_plan: Plan, constraint_list: list = None, opt_params:
287288 df .at [count , 'volume_perc' ] = dvh_updated_list [i ]['constraints' ][goal_key ]
288289 df .at [count , 'dvh_type' ] = 'goal'
289290 df .at [count , 'weight' ] = dvh_updated_list [i ]['parameters' ]['weight' ]
291+ df .at [count , 'bound_type' ] = dvh_updated_list [i ]['constraints' ].get ('bound_type' , 'upper' )
290292 count = count + 1
291293 if 'dose_volume_D' in dvh_updated_list [i ]['type' ]:
292294 limit_key = self .matching_keys (dvh_updated_list [i ]['constraints' ], 'limit' )
@@ -295,6 +297,7 @@ def get_dvh_table(self, my_plan: Plan, constraint_list: list = None, opt_params:
295297 df .at [count , 'volume_perc' ] = dvh_updated_list [i ]['parameters' ]['volume_perc' ]
296298 df .at [count , 'dose_gy' ] = self .dose_to_gy (limit_key , dvh_updated_list [i ]['constraints' ][limit_key ])
297299 df .at [count , 'dvh_type' ] = 'constraint'
300+ df .at [count , 'bound_type' ] = dvh_updated_list [i ]['constraints' ].get ('bound_type' , 'upper' )
298301 count = count + 1
299302 goal_key = self .matching_keys (dvh_updated_list [i ]['constraints' ], 'goal' )
300303 if goal_key in dvh_updated_list [i ]['constraints' ]:
@@ -303,6 +306,7 @@ def get_dvh_table(self, my_plan: Plan, constraint_list: list = None, opt_params:
303306 df .at [count , 'dose_gy' ] = self .dose_to_gy (goal_key , dvh_updated_list [i ]['constraints' ][goal_key ])
304307 df .at [count , 'dvh_type' ] = 'goal'
305308 df .at [count , 'weight' ] = dvh_updated_list [i ]['parameters' ]['weight' ]
309+ df .at [count , 'bound_type' ] = dvh_updated_list [i ]['constraints' ].get ('bound_type' , 'upper' )
306310 count = count + 1
307311 self .dvh_table = df
308312 self .get_max_tol (constraints_list = constraint_list )
@@ -339,15 +343,25 @@ def get_low_dose_vox_ind(self, my_plan: Plan, dose: np.ndarray, inf_matrix: Infl
339343 volume percentage.
340344 """
341345 dvh_table = self .dvh_table
342- inf_matrix = my_plan .inf_matrix
346+ if inf_matrix is None :
347+ inf_matrix = my_plan .inf_matrix
343348 for ind in dvh_table .index :
344349 structure_name , dose_gy , vol_perc = dvh_table ['structure_name' ][ind ], dvh_table ['dose_gy' ][ind ], \
345350 dvh_table ['volume_perc' ][ind ]
346351 dvh_type = dvh_table ['dvh_type' ][ind ]
352+ bound_type = dvh_table .at [ind , 'bound_type' ] if 'bound_type' in dvh_table .columns else 'upper'
347353 vol_perc = vol_perc / inf_matrix .get_fraction_of_vol_in_calc_box (structure_name )
348354 struct_vox = inf_matrix .get_opt_voxels_idx (structure_name )
349355 n_struct_vox = len (struct_vox )
350- sort_ind = np .argsort (dose [struct_vox ])
356+ # sort_ind = np.argsort(dose[struct_vox])
357+ if bound_type == 'lower' :
358+ # For lower bound (e.g., PTV coverage), pick HIGHEST-dose voxels up to p%
359+ sort_ind = np .argsort (- dose [struct_vox ]) # descending
360+ target_perc = vol_perc # accumulate to p%
361+ else :
362+ # Original behavior (upper bound): pick LOWEST-dose voxels up to (100 - p)%
363+ sort_ind = np .argsort (dose [struct_vox ]) # ascending
364+ target_perc = 100 - vol_perc # accumulate to (100 - p)%
351365 voxel_sort = struct_vox [sort_ind ]
352366 weights = inf_matrix .get_opt_voxels_volume_cc (structure_name )
353367 weights_sort = weights [sort_ind ]
@@ -357,7 +371,7 @@ def get_low_dose_vox_ind(self, my_plan: Plan, dose: np.ndarray, inf_matrix: Infl
357371 for w_ind in range (n_struct_vox ):
358372 w_sum = w_sum + weights_sort [w_ind ]
359373 w_ratio = w_sum / weight_all_sum
360- if w_ratio * 100 >= ( 100 - vol_perc ) :
374+ if w_ratio * 100 >= target_perc :
361375 break
362376 low_dose_voxels = voxel_sort [:w_ind + 1 ]
363377 if ind == 0 :
0 commit comments