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/07/10 14:11] – [Python] dpatenaude | dosimetry:userguide:thinknode [2021/07/29 18:23] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 5: | Line 5: | ||
====== Python ====== | ====== Python ====== | ||
+ | |||
+ | Please refer to the [[https:// | ||
+ | ===== Python: Overview ===== | ||
+ | |||
The provided python scripts and libraries are meant to be a foundation and starting point for using the astroid apps on the thinknode™ framework. The provided scripts outline the basics of using ISS to store objects, as well as constructing and making calculation requests to the calculation provider. The below sections detail the basic usage for each script. | The provided python scripts and libraries are meant to be a foundation and starting point for using the astroid apps on the thinknode™ framework. The provided scripts outline the basics of using ISS to store objects, as well as constructing and making calculation requests to the calculation provider. The below sections detail the basic usage for each script. | ||
Line 16: | Line 20: | ||
* // | * // | ||
* //api_url// being the connection string to the thinknode™ framework. | * //api_url// being the connection string to the thinknode™ framework. | ||
- | * // | + | |
- | * // | + | |
+ | * // | ||
+ | * // | ||
+ | * // | ||
+ | * // | ||
<code json thinknode.cfg> | <code json thinknode.cfg> | ||
{ | { | ||
- | " | + | " |
- | " | + | " |
- | "app_name": " | + | "apps": |
- | " | + | { |
- | " | + | |
+ | | ||
+ | | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | }, | ||
+ | " | ||
+ | " | ||
} | } | ||
- | |||
</ | </ | ||
===== Python: Immutable Storage ===== | ===== Python: Immutable Storage ===== | ||
==== Post Generic ISS Object ==== | ==== Post Generic ISS Object ==== | ||
- | The // | + | The // |
Dependencies: | Dependencies: | ||
* [[dosimetry: | * [[dosimetry: | ||
* [[dosimetry: | * [[dosimetry: | ||
- | * compute_aperture_creation_params.json (or any other prebuilt json file of a dosimetry object as described in the [[http:// | + | * study.json (or any other prebuilt json file of a dosimetry object as described in the [[http:// |
<code python post_iss_object_generic.py> | <code python post_iss_object_generic.py> | ||
Line 44: | Line 68: | ||
from lib import thinknode_worker as thinknode | from lib import thinknode_worker as thinknode | ||
- | from lib import decimal_logging as dl | ||
import requests | import requests | ||
import json | import json | ||
iss_dir = " | iss_dir = " | ||
- | json_iss_file = "aperture_creation_params.json" | + | json_iss_file = "study.json" |
- | obj_name = "aperture_creation_params" | + | obj_name = "rt_study" |
# Get IAM ids | # Get IAM ids | ||
Line 60: | Line 83: | ||
# Post immutable object to ISS | # Post immutable object to ISS | ||
- | res = thinknode.post_immutable(iam, json_data, obj_name) | + | res = thinknode.post_immutable_named(iam, " |
- | dl.data(" | + | |
</ | </ | ||
Line 81: | Line 103: | ||
# Copyright (c) 2015 .decimal, Inc. All rights reserved. | # Copyright (c) 2015 .decimal, Inc. All rights reserved. | ||
# Desc: Post a json calculation request to the thinknode framework | # Desc: Post a json calculation request to the thinknode framework | ||
- | |||
- | from lib import thinknode_worker as thinknode | ||
- | from lib import decimal_logging as dl | ||
- | import requests | ||
- | import json | ||
request_dir = " | request_dir = " | ||
Line 98: | Line 115: | ||
# Send calc request and wait for answer | # Send calc request and wait for answer | ||
- | res = thinknode.do_calculation(iam, | + | res = thinknode.do_calculation(iam, |
- | dl.data(" | + | dl.data(" |
</ | </ | ||
Line 118: | 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 131: | 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 165: | 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 212: | 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 222: | Line 212: | ||
| | ||
# Perform calculation | # Perform calculation | ||
- | res = thinknode.do_calculation(iam, | + | res = thinknode.do_calculation(iam, |
- | dl.data(" | + | dl.data(" |
</ | </ | ||
===== Python: decimal Libraries ===== | ===== Python: decimal Libraries ===== | ||
Line 229: | 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 | |
- | Below you will see as snippet from the rt_types module that shows the class for the //aperture_creation_params// dosimetry 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 data |
- | s = triangle_mesh() | + | |
+ | def from_json(self, | ||
+ | for k, v in jdict.items(): | ||
+ | if hasattr(self, | ||
+ | setattr(self, | ||
+ | |||
+ | class polyset(object): | ||
+ | |||
+ | # | ||
+ | def __init__(self): | ||
+ | self.polygons = [] | ||
+ | self.holes = [] | ||
+ | |||
+ | def expand_data(self): | ||
+ | data = {} | ||
+ | polygon | ||
+ | for x in self.polygons: | ||
+ | s = polygon2() | ||
s.from_json(x) | s.from_json(x) | ||
- | target.append(s.expand_data()) | + | polygon.append(s.expand_data()) |
- | data[' | + | data[' |
- | data[' | + | hole = [] |
- | data[' | + | for x in self.holes: |
- | data[' | + | s = polygon2() |
- | organ | + | |
- | for x in self.organs: | + | |
- | s = aperture_organ() | + | |
s.from_json(x) | s.from_json(x) | ||
- | organ.append(s.expand_data()) | + | hole.append(s.expand_data()) |
- | data[' | + | data[' |
- | half_plane = [] | + | |
- | for x in self.half_planes: | + | |
- | s = aperture_half_plane() | + | |
- | s.from_json(x) | + | |
- | half_plane.append(s.expand_data()) | + | |
- | 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) | + | |
- | centerline.append(s.expand_data()) | + | |
- | data[' | + | |
- | override = [] | + | |
- | for x in self.overrides: | + | |
- | s = aperture_manual_override() | + | |
- | s.from_json(x) | + | |
- | override.append(s.expand_data()) | + | |
- | data[' | + | |
- | data[' | + | |
return data | return data | ||
Line 301: | 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 ==== | ||
- | 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 346: | 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 353: | 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.1436537484.txt.gz · Last modified: 2021/07/29 18:21 (external edit)