dosimetry:userguide:thinknode
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
dosimetry:userguide:thinknode [2015/09/24 12:21] – [Generic Calc Request] dpatenaude | dosimetry:userguide:thinknode [2021/07/29 18:23] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 6: | Line 6: | ||
====== Python ====== | ====== Python ====== | ||
+ | Please refer to the [[https:// | ||
===== Python: Overview ===== | ===== Python: Overview ===== | ||
Line 134: | Line 135: | ||
=== Example === | === Example === | ||
- | Below is an abbreviated version of the //post_calc_request_sobp_dose.py// file. The abbreviated sections are denoted as " | + | Below is an abbreviated version of the //post_calc_request_sobp_dose_with_shifter.py// file. The abbreviated sections are denoted as " |
- | In the below sample, the // | + | In the below sample, the // |
* Modules used and explanation: | * Modules used and explanation: | ||
- | * The // | ||
* The // | * The // | ||
+ | * The // | ||
* The // | * The // | ||
Line 147: | Line 148: | ||
import json | import json | ||
from lib import thinknode_worker as thinknode | from lib import thinknode_worker as thinknode | ||
+ | from lib import dosimetry_worker as dosimetry | ||
from lib import decimal_logging as dl | from lib import decimal_logging as dl | ||
- | from lib import rt_types as rt_types | ||
# Get IAM ids | # Get IAM ids | ||
iam = thinknode.authenticate(thinknode.read_config(' | iam = thinknode.authenticate(thinknode.read_config(' | ||
- | def make_grid(corner, size, spacing): | + | def make_dose_points(pointCount): |
... | ... | ||
- | def make_water_phantom(corner, size, spacing): | + | def make_layers(sad, range, mod): |
return \ | return \ | ||
- | thinknode.function(" | + | thinknode.function(iam[" |
[ | [ | ||
- | | + | |
- | thinknode.value(1), | + | thinknode.value(sad), |
- | thinknode.value(" | + | thinknode.value(range), |
+ | thinknode.value(mod) | ||
]) | ]) | ||
- | |||
- | def make_dose_points(pointCount): | ||
- | ... | ||
- | |||
- | def get_example_sobp_machine(id): | ||
- | ... | ||
- | |||
- | def make_layers(sad, | ||
- | ... | ||
def make_target(): | def make_target(): | ||
Line 181: | Line 174: | ||
thinknode.value([16, | thinknode.value([16, | ||
]) | ]) | ||
- | |||
- | def make_view(): | ||
- | ds = rt_types.box_2d() | ||
- | ds.corner = [-100, -100] | ||
- | ds.size = [200, 200] | ||
- | |||
- | mv = rt_types.multiple_source_view() | ||
- | mv.display_surface = ds | ||
- | mv.center = [0, 0, 0] | ||
- | mv.direction = [0, 1, 0] | ||
- | mv.distance = [2270, 2270] | ||
- | mv.up = [0, 0, 1] | ||
- | |||
- | return mv | ||
def compute_aperture(): | def compute_aperture(): | ||
- | | + | |
- | + | ||
- | # ap_params.targets.append(thinknode.reference(" | + | |
- | ap_params.targets.append(make_target()) | + | |
- | + | ||
- | # Make aperture_creation_params | + | |
- | args = {} | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | args[" | + | |
- | + | ||
- | return \ | + | |
- | thinknode.function(" | + | |
- | [ | + | |
- | thinknode.structure_named_type(" | + | |
- | ]) | + | |
beam_geometry = \ | beam_geometry = \ | ||
... | ... | ||
+ | |||
+ | # Get degrader geometry as calculation result | ||
+ | degrade_geom = \ | ||
+ | thinknode.function(iam[" | ||
+ | [ | ||
+ | thinknode.value(18), | ||
+ | thinknode.value(" | ||
+ | thinknode.value(200) # downstream edge | ||
+ | ]) | ||
+ | res_geom = thinknode.do_calculation(iam, | ||
+ | degrader = \ | ||
+ | thinknode.function(iam[" | ||
+ | [ | ||
+ | thinknode.value(res_geom), | ||
+ | thinknode.reference(" | ||
+ | ]) | ||
+ | proton_degr = thinknode.do_calculation(iam, | ||
# Call compute_sobp_pb_dose2 | # Call compute_sobp_pb_dose2 | ||
Line 228: | Line 202: | ||
thinknode.function(" | thinknode.function(" | ||
[ | [ | ||
- | | + | |
thinknode.value(make_dose_points(181)), | thinknode.value(make_dose_points(181)), | ||
beam_geometry, | beam_geometry, | ||
- | make_grid([-75, | + | |
make_layers(2270.0, | make_layers(2270.0, | ||
compute_aperture(), | compute_aperture(), | ||
Line 238: | Line 212: | ||
| | ||
# Perform calculation | # Perform calculation | ||
- | res = thinknode.do_calculation(iam, | + | res = thinknode.do_calculation(iam, |
dl.data(" | dl.data(" | ||
</ | </ | ||
Line 245: | Line 219: | ||
==== rt_types ==== | ==== rt_types ==== | ||
- | The // | + | The // |
Each data type detailed in the [[http:// | Each data type detailed in the [[http:// | ||
- | + | Below you will see a snippet from the rt_types module that shows the class for the //polyset// rt_type along with its default | |
- | Below you will see as snippet from the rt_types module that shows the class for the //aperture_creation_params// rt_type along with its default | + | |
- | * **Interdependence: | + | |
- | * **//out// function:** Each class' | + | |
<code python> | <code python> | ||
- | class aperture_creation_params(object): | + | class polygon2(object): |
# | # | ||
def __init__(self): | def __init__(self): | ||
- | self.targets | + | blob = blob_type() |
- | self.target_margin | + | self.vertices |
- | self.view = multiple_source_view() | + | |
- | self.mill_radius = 0.0 | + | |
- | self.organs = [] | + | |
- | self.half_planes = [] | + | |
- | self.corner_planes = [] | + | |
- | self.centerlines = [] | + | |
- | self.overrides = [] | + | |
- | self.downstream_edge = 0.0 | + | |
def expand_data(self): | def expand_data(self): | ||
data = {} | data = {} | ||
- | target = [] | + | data[' |
- | for x in self.targets: | + | return |
- | s = triangle_mesh() | + | |
- | s.from_json(x) | + | def from_json(self, jdict): |
- | target.append(s.expand_data()) | + | for k, v in jdict.items(): |
- | data['targets' | + | if hasattr(self,k): |
- | data[' | + | setattr(self, k, v) |
- | data[' | + | |
- | data[' | + | class polyset(object): |
- | organ = [] | + | |
- | for x in self.organs: | + | # |
- | s = aperture_organ() | + | def __init__(self): |
- | s.from_json(x) | + | self.polygons |
- | organ.append(s.expand_data()) | + | self.holes = [] |
- | data[' | + | |
- | half_plane = [] | + | def expand_data(self): |
- | for x in self.half_planes: | + | data = {} |
- | s = aperture_half_plane() | + | polygon |
- | s.from_json(x) | + | for x in self.polygons: |
- | half_plane.append(s.expand_data()) | + | s = polygon2() |
- | data[' | + | |
- | corner_plane | + | |
- | for x in self.corner_planes: | + | |
- | s = aperture_corner_plane() | + | |
- | s.from_json(x) | + | |
- | corner_plane.append(s.expand_data()) | + | |
- | data[' | + | |
- | centerline | + | |
- | for x in self.centerlines: | + | |
- | s = aperture_centerline() | + | |
s.from_json(x) | s.from_json(x) | ||
- | centerline.append(s.expand_data()) | + | polygon.append(s.expand_data()) |
- | data[' | + | data[' |
- | override | + | hole = [] |
- | for x in self.overrides: | + | for x in self.holes: |
- | s = aperture_manual_override() | + | s = polygon2() |
s.from_json(x) | s.from_json(x) | ||
- | override.append(s.expand_data()) | + | hole.append(s.expand_data()) |
- | data[' | + | data[' |
- | data[' | + | |
return data | return data | ||
Line 317: | Line 269: | ||
for k, v in jdict.items(): | for k, v in jdict.items(): | ||
if hasattr(self, | if hasattr(self, | ||
- | if k == ' | + | setattr(self, |
- | self.view.from_json(v) | + | </ |
- | else: | + | |
- | setattr(self, k, v) | + | * **Interdependence:** When rt_types are constructed of other or multiple named types, they will be constructed as such in each class as seen in the // |
+ | * **// | ||
+ | * **// | ||
+ | |||
+ | Below is an example usage of getting a thinknode dose image (image_3d data type in the astroid manifest) and turning it into a rt_types image_3d data type, so that it can be expanded and then used to output the image into a VTK graphics file: | ||
+ | |||
+ | <code python> | ||
+ | def dose_to_vtk(dose_id): | ||
+ | img_data = json.loads(thinknode.get_immutable(iam, ' | ||
+ | |||
+ | img = rt_types.image_3d() | ||
+ | img.from_json(img_data) | ||
+ | img2 = img.expand_data() | ||
+ | |||
+ | vtk.write_vtk_image3(' | ||
</ | </ | ||
==== thinknode_worker ==== | ==== thinknode_worker ==== | ||
Line 326: | Line 292: | ||
The // | The // | ||
- | Refer to the [[https:// | + | Refer to the [[https:// |
<code python> | <code python> | ||
- | # Authenticate with thinknode and store necessary ids | + | # Authenticate with thinknode and store necessary ids. |
- | # Gets the realm_id, bucket_id, and context_id | + | # Gets the context id for each app detailed in the thinknode config |
+ | # Gets the app version (if non defined) for each app in the realm | ||
# param config: connection settings (url and unique basic user authentication) | # param config: connection settings (url and unique basic user authentication) | ||
def authenticate(config): | def authenticate(config): | ||
- | # Send calculation request to thinknode | + | # Send calculation request to thinknode |
+ | # calculation is performed again, the calculation | ||
+ | # does not have to be repeatedly pulled from thinknode. Saves one calculation time and bandwidth. | ||
+ | # note: see post_calculation if you just want the calculation ID and don't need to wait for the calculation to finish or get results | ||
# param config: connection settings (url, user token, and ids for context and realm) | # param config: connection settings (url, user token, and ids for context and realm) | ||
# param json_data: calculation request in json format | # param json_data: calculation request in json format | ||
- | # param return_data: | + | # param return_data: |
- | def do_calculation(config, | + | # param return_error: |
+ | def do_calculation(config, | ||
- | # Post immutable object to ISS | + | # Post immutable |
# param config: connection settings (url, user token, and ids for context and realm) | # param config: connection settings (url, user token, and ids for context and realm) | ||
+ | # param app_name: name of the app to use to get the context id from the iam config | ||
# param json_data: immutable object in json format | # param json_data: immutable object in json format | ||
# param obj_name: object name of app to post to | # param obj_name: object name of app to post to | ||
- | def post_immutable(config, json_data, obj_name): | + | def post_immutable_named(config, app_name, json_data, obj_name): |
+ | scope = '/ | ||
+ | return post_immutable(config, | ||
# Post immutable object to ISS | # Post immutable object to ISS | ||
# param config: connection settings (url, user token, and ids for context and realm) | # param config: connection settings (url, user token, and ids for context and realm) | ||
+ | # param app_name: name of the app to use to get the context id from the iam config | ||
# param obj_id: thinknode iss reference id for object to get | # param obj_id: thinknode iss reference id for object to get | ||
- | def get_immutable(config, | + | def get_immutable(config, app_name, obj_id): |
+ | </ | ||
+ | |||
+ | ==== dosimetry_worker ==== | ||
+ | The dosimetry_worker module provides high-level functions for building data types and calculation requests for common dosimetry tasks. This library is constantly growing as more routine tasks are programmed in python. | ||
+ | |||
+ | Refer to the [[https:// | ||
+ | |||
+ | - Aperture creation (using structures/ | ||
+ | - Dose comparison | ||
+ | - Grid creation | ||
+ | - Image creation | ||
+ | - PBS Spot functions | ||
+ | |||
+ | |||
+ | ==== vtk_worker ==== | ||
+ | The VTK worker provides a means to write out common rt_types to a vtk file format ([[http:// | ||
+ | |||
+ | Below is an example of turning a dose image_3d into a vtk file for visualization in Paraview: | ||
+ | |||
+ | <code python> | ||
+ | def dose_to_vtk(dose_id): | ||
+ | img_data = json.loads(thinknode.get_immutable(iam, | ||
+ | |||
+ | img = rt_types.image_3d() | ||
+ | img.from_json(img_data) | ||
+ | img2 = img.expand_data() | ||
+ | |||
+ | vtk.write_vtk_image3(' | ||
</ | </ | ||
==== decimal_logging ==== | ==== decimal_logging ==== | ||
- | The // | + | The // |
The following settings are available in the decimal_logging.py file: | The following settings are available in the decimal_logging.py file: | ||
Line 362: | Line 365: | ||
**display_types: | **display_types: | ||
**log_file: ** sets the logfile name and location | **log_file: ** sets the logfile name and location | ||
+ | |||
+ | === Debugging === | ||
+ | |||
+ | When debugging, use the dl.debug() function and set the //isDebug// flag in the decimal_logging library to True. This toggles on the output for each of the dl.debug calls. By default we keep debugging off, but it can be turned on as needed. | ||
+ | |||
+ | === Other Flags === | ||
+ | |||
The following image shows the logging settings for each message type as: | The following image shows the logging settings for each message type as: | ||
Line 369: | Line 379: | ||
{{ dosimetry: | {{ dosimetry: | ||
+ | |||
+ | === File Logging === | ||
+ | |||
+ | The decimal_logging library also provides simple file logging. The // | ||
+ | |||
+ | * log(message) | ||
+ | * log_debug_data(message, | ||
+ | * log_data(data) | ||
+ | |||
---- | ---- | ||
<WRAP center 10%>// | <WRAP center 10%>// | ||
<WRAP center 40%> | <WRAP center 40%> |
dosimetry/userguide/thinknode.1443097288.txt.gz · Last modified: 2021/07/29 18:21 (external edit)