User Tools

Site Tools


dosimetry:userguide:thinknode

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
dosimetry:userguide:thinknode [2015/07/10 12:50] – [SOBP Dose Calculation] dpatenaudedosimetry:userguide:thinknode [2021/07/29 18:23] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== thinknode™ Examples ====== ====== thinknode™ Examples ======
  
-These examples provide a starting point for issuing http connections and requests to the dosimetry app on the thinknode™ framework. They are provided as is, and are written in python and c++. Any further dependencies are listed along with the provided scripts.+These examples provide a starting point for issuing http connections and requests to the dosimetry app on the thinknode™ framework. They are provided as is, and are written in python. Any further dependencies are listed along with the provided scripts.
  
-====== C++ ====== 
  
-A simple C++ project that handles posting immutable objects and calculation requests to thinknode™ framework. The //main()// function toggles on which task to perform. Below are the defined functions of the project as well as a link to download the file in its entirety.+====== Python ======
  
-Dependencies: +Please refer to the [[https://github.com/dotdecimal/astroid-script-library/blob/development/python/README.mdPython Script Library Readme]] for dependent python modules and a high level list of what these libraries include. 
-  * [[http://curl.haxx.se/libcurl/c/example.html|libcurl]] +===== Python: Overview =====
-  * [[https://github.com/open-source-parsers/jsoncpp|jsoncpp]]+
  
-===thinknode.cpp=== 
  
-  * {{dosimetry:userguide:thinknode.cpp|}} +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. 
- +
-<code cpp> +
-// Copyright (c) 2015 .decimal, Inc. All rights reserved. +
-// Desc:     Worker to perform tasks on thinknode framework +
- +
-#include "stdafx.h" +
-#include <stdio.h> +
-#include <string.h> +
-#include <iostream> +
-#include <fstream> +
-#include <sstream> +
-#include <json/json.h> +
- +
-#define CURL_STATICLIB +
-#include <curl/curl.h> +
- +
-using namespace std; +
- +
-// API configuration +
-string basic_user = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";    // Base64 encoded username:password +
-string api_url = "https://api.thinknode.com/v1.0";         // thinknode url +
-string app_name = "Dosimetry";                             // app name +
-string app_version = "1.0.0";                              // app version +
- +
-// Curl get request call back +
-static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) +
-... +
- +
-// Select a specific json tag into string +
-string get_json_value(string json, string id, int num = 0) +
-... +
- +
-// Curllib get http request +
-string do_curl_get(string auth, string url) +
-... +
- +
-// Curllib post http request +
-string do_curl_post(string auth, string json, string url) +
-... +
- +
-// Handles http request to get the user ID from the basic_user +
-string get_user_token() +
-... +
- +
-// Handles http request for realm id +
-string get_realm_id(string token) +
-... +
- +
-// Handles http request for context id +
-string get_context_id(std::map<string, string> config) +
-... +
- +
-// API Authentication +
-std::map<string, string> authenticate() +
-... +
- +
-// Grab and post the specified calc request +
-void post_calc_request() +
-... +
- +
-// Grab and post sepcified object to the ISS +
-void post_immutable_object() +
-... +
- +
-int main(void) +
-... +
- +
-</code> +
- +
-===== C++: Immutable Storage ===== +
- +
- +
-The below example is a function in the [[dosimetry:userguide:thinknode#thinknode.cpp|thinknode.cpp]] class to post an immutable object to the dosimetry app on the thinknode™ framework. This example can be used for any immutable storage post using any datatype by replacing the json iss file. +
- +
- +
-Dependencies: +
-  * {{dosimetry:userguide:aperture_creation_params.json|compute_aperture_creation_params.json}} +
- +
-<code cpp> +
-void post_immutable_object() +
-+
-    // Immutable info +
-    string path = "C:\\";                                    // Path of folder json file is located in +
-    string sjon_iss_file = "aperture_creation_params.json";  // local json object file +
-    string obj_name = "aperture_creation_params";            // app named_type +
- +
-    std::map<string, string> iam = authenticate(); +
- +
-    // Read local immutable json file +
-    std::ifstream json_file((path + sjon_iss_file).c_str()); +
-    string str((std::istreambuf_iterator<char>(json_file)), std::istreambuf_iterator<char>());     +
-     +
-    // Post object +
-    std::cout << "Posting Object to ISS..." << std::endl; +
-    string authentication_string = "Authorization : Bearer " + iam["user_token"]; +
-    string res = do_curl_post( +
-        authentication_string,  +
-        str,  +
-        api_url + "/iss/named/" + app_name + "/" + obj_name + "/?context=" + iam["context_id"]); +
-    std::cout << "Immuntable ID: " << res << std::endl;    +
-+
-</code> +
- +
-**Returns:** +
-  - The ID (in json) of the object stored in Immutable Storage. +
- +
-===== C++: Calculation Request ===== +
- +
-The below example is a function in the [[dosimetry:userguide:thinknode#thinknode.cpp|thinknode.cpp]] class to post a calculation request to dosimetry. This example can be used for any calculation request using any datatype by replacing the calculation request json file. This request will post a calculation request, check the status using long polling with a specified timeout, and return the calculation result. +
- +
-Dependencies: +
-  * {{dosimetry:userguide:compute_aperture.json|compute_aperture.json}} +
- +
-<code cpp> +
-void post_calc_request() +
-+
-    // Request info +
-    string path = "C:\\";                            // Path of folder json file is located in +
-    string sjon_iss_file = "compute_aperture.json";  // local json calc request +
- +
-    std::map<string, string> iam = authenticate(); +
- +
-    std::ifstream json_file((path + sjon_iss_file).c_str()); +
-    string str((std::istreambuf_iterator<char>(json_file)), std::istreambuf_iterator<char>());  +
-     +
-    string authentication_string = "Authorization : Bearer " + iam["user_token"]; +
-    // Get calculation id +
-    std::cout << "Sending Calculation..." << std::endl; +
-    string calculation_id = get_json_value( +
-        do_curl_post(authentication_string,  +
-        str, api_url + "/calc/?context=" + iam["context_id"]),  +
-        "id"); +
- +
-    // Get calculation Status - using long polling +
-    std::cout << "Checking Calculation Status..." << std::endl; +
-    string calculation_status = get_json_value( +
-        do_curl_get(authentication_string,  +
-        api_url + "/calc/" + calculation_id + "/status/?status=completed&progress=1&timeout=5"),  +
-        "type"); +
-    if (calculation_status.find("failed") != string::npos)  +
-    {  +
-        std::cout << "Server Responded: " << calculation_status << std::endl;  +
-        return;  +
-    } +
- +
-    // Get calculation Result +
-    std::cout << "Fetching Calculation Result..." << std::endl; +
-    string calculation_result = do_curl_get( +
-        authentication_string,  +
-        api_url + "/calc/" + calculation_id + "/result/?context=" + iam["context_id"]); +
- +
-    std::cout << "Calculation Result: " << calculation_result << std::endl; +
-+
-</code> +
- +
-**Returns:** +
-  - The calculation result (in json) of the API function called. +
-====== Python ====== +
- +
-The provided python scripts and libraries are meant to be a foundation and starting point for using the astroid Dosimetry app 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. +
  
 **Download:** The python astroid_script_library can be downloaded from the [[https://github.com/dotdecimal/astroid-script-library|.decimal GitHub repository]]. **Download:** The python astroid_script_library can be downloaded from the [[https://github.com/dotdecimal/astroid-script-library|.decimal GitHub repository]].
Line 179: Line 16:
 ====thinknode.cfg==== ====thinknode.cfg====
  
-There is a simple configuration file (thinknode.cfg) that is used to store user data for connecting to the Dosimetry app on the thinknode™ framework. This file is required by all scripts in the python astroid_script_library to authenticate and use the Dosimetry app. A sample file with no user data is available in the repository and the details of the information to include in the file are provided below.  +There is a simple configuration file (thinknode.cfg) that is used to store user data for connecting to the astroid app on the thinknode™ framework. This file is required by all scripts in the python astroid_script_library to authenticate and use the app. A sample file with no user data is available in the repository and the details of the information to include in the file are provided below.  
  
   * //basic_user// being a base64 encoded username and password. Refer to the [[http://www.developers.thinknode.com|thinknode documentation]] for more information.   * //basic_user// being a base64 encoded username and password. Refer to the [[http://www.developers.thinknode.com|thinknode documentation]] for more information.
   * //api_url// being the connection string to the thinknode™ framework.   * //api_url// being the connection string to the thinknode™ framework.
-  * //app_name// being the current app name (e.g. dosimetry). +  * //apps// 
-  * //app_version// being the current version of dosimetry existing on the thinknode™ framework being used.+    * //app_name// being the current app name (e.g. dosimetry or dicom). 
 +      * //app_version// being the current version of the app existing on the thinknode™ framework being used. If left blank the thinknode_worker will select the first app's version returned by the Realm Versions GET request. 
 +      * //branch_name// not currently implemented 
 +  * //realm_name// thinknode realm 
 +  * //account_name// thinknode account name
  
 <code json thinknode.cfg> <code json thinknode.cfg>
 { {
-    "basic_user": "<Base64 encoded username:password>", +    "basic_user": "<Base64 encoded thinknode username:password>", 
-    "api_url": "https://api.thinknode.com/v1.0", +    "api_url": "https://<thinknode_account>.thinknode.io/api/v1.0", 
-    "app_name": "dosimetry", +    "apps": 
-    "app_version": "1.0.0.0", +    {    
-    "realm_name": "Realm Name"+        "dosimetry" 
 +            
 +            "app_version": "1.0.0-beta1"
 +            "branch_name": "master" 
 +        }, 
 +        "dicom": 
 +        { 
 +            "app_version": "", 
 +            "branch_name": "master"        
 +        }, 
 +        "rt_types": 
 +        { 
 +            "app_version": "", 
 +            "branch_name": "master"          
 +        } 
 +    },  
 +    "realm_name": "<thinknode realm>", 
 +    "account_name": "<thinknode account>"
 } }
- 
 </code> </code>
 ===== Python: Immutable Storage ===== ===== Python: Immutable Storage =====
 ==== Post Generic ISS Object ==== ==== Post Generic ISS Object ====
  
-The //post_iss_object_generic.py// is a basic python script that provides an example to post any dosimetry type as an immutable object to the dosimetry app on the thinknode™ framework. This example can be used for any immutable storage post using any datatype by replacing the json iss file. The current example posts an aperture_creation_params datatype object that is read in from the aperture_creation_params.json data file.+The //post_iss_object_generic.py// is a basic python script that provides an example to post any dosimetry type as an immutable object to the dosimetry app on the thinknode™ framework. This example can be used for any immutable storage post using any datatype by replacing the json iss file. The current example posts an rt_study DICOM App datatype object that is read in from the study.json data file.
  
 Dependencies: Dependencies:
   * [[dosimetry:userguide:thinknode#thinknodecfg|thinknode.cfg]]    * [[dosimetry:userguide:thinknode#thinknodecfg|thinknode.cfg]] 
   * [[dosimetry:userguide:thinknode##pythondecimal_libraries|.decimal Python Libraries]]    * [[dosimetry:userguide:thinknode##pythondecimal_libraries|.decimal Python Libraries]] 
-  * compute_aperture_creation_params.json (or any other prebuilt json file of a dosimetry object as described in the [[http://docs.apps.dotdecimal.com|Dosimetry Manifest Guide]])+  * study.json (or any other prebuilt json file of a dosimetry object as described in the [[http://docs.apps.dotdecimal.com|Apps Manifest Guide]])
  
 <code python post_iss_object_generic.py> <code python post_iss_object_generic.py>
Line 211: 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_files" iss_dir = "iss_files"
-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 227: 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, "dicom", json_data, obj_name)
-dl.data("Immutable id: ", res.text)+
  
 </code> </code>
Line 248: 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_files" request_dir = "request_files"
Line 265: Line 115:
  
 # Send calc request and wait for answer # Send calc request and wait for answer
-res = thinknode.do_calculation(iam, json_data, True+res = thinknode.do_calculation(iam, json_data) 
-dl.data("Calculation Result: ", res.text)+dl.data("Calculation Result: ", str(res))
 </code> </code>
  
Line 285: 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 //dose_calc// variable is a thinknode function request that is made of individually constructed arguments. Notice how the compute_aperture() thinknode request function is created using the //aperture_creation_params// class defined in the dosimetry_types module allowing for easier dosimetry type creation and code readability. Also note that //aparams.view// is comprised of another class//multiple_source_view//defined from the dosimetry_types module+In the below sample, the //dose_calc// variable is a thinknode function request that is made of individually constructed arguments. Notice how some of the elementslike degradercan be built upon seperate calculation requests.
  
   * Modules used and explanation:   * Modules used and explanation:
-    * The //dosimetry_types// (dt) module is a class library of all the dosimetry data types as described in the [[http://docs.apps.dotdecimal.com|Dosimetry Manifest Guide]]. This library provides easier manual construction of the dosimetry data types.  
     * The //thinknode_worker// (thinknode) module is a library that provides worker functions for performing and building the authentication, iss, and calculation requests to the thinknode framework.     * The //thinknode_worker// (thinknode) module is a library that provides worker functions for performing and building the authentication, iss, and calculation requests to the thinknode framework.
 +    * The //dosimetry_worker// (dosimetry) module is a library that provides simplified common dosimetry tasks.
     * The //decimal_logger// (dl) module is a library that provides nicely formatted log output. This includes optional file logging, timestamps, and message coloring (when run through command windows).     * The //decimal_logger// (dl) module is a library that provides nicely formatted log output. This includes optional file logging, timestamps, and message coloring (when run through command windows).
  
Line 298: 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('thinknode.cfg')) iam = thinknode.authenticate(thinknode.read_config('thinknode.cfg'))
  
-def make_grid(corner, size, spacing):+def make_dose_points(pointCount):
 ... ...
  
-def make_water_phantom(cornersizespacing):+def make_layers(sadrangemod):
     return \     return \
-        thinknode.function("dosimetry", "create_uniform_image_on_grid_3d",+        thinknode.function(iam["account_name"], "dosimetry", "compute_double_scattering_layers",
             [             [
-                make_grid(corner, sizespacing), +                thinknode.reference("55f70f5000c0a247563a909b6087ada0")# SOBP Machine from ISS 
-                thinknode.value(1), +                thinknode.value(sad), 
-                thinknode.value("relative_stopping_power")+                thinknode.value(range), 
 +                thinknode.value(mod)
             ])             ])
- 
-def make_dose_points(pointCount): 
-... 
- 
-def get_example_sobp_machine(id): 
-... 
- 
-def make_layers(sad, range, mod): 
-... 
  
 def make_target(): def make_target():
Line 332: Line 174:
                 thinknode.value([16, -10, 30])                 thinknode.value([16, -10, 30])
             ])             ])
- 
-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 = rt_types.aperture_creation_params() +    return dosimetry.compute_aperture(iam, make_target(), beam_geometry, 20.00.0250.5)
- +
-    # ap_params.targets.append(thinknode.reference("55802bcf49400020000c")) # Use existing ISS target +
-    ap_params.targets.append(make_target()+
- +
-    # Make aperture_creation_params +
-    args = {} +
-    args["targets"] = thinknode.array_named_type("rt_types""triangle_mesh"ap_params.targets) +
-    args["target_margin"] = thinknode.value(20.0+
-    args["view"] = thinknode.value(thinknode.to_json(make_view())) +
-    args["mill_radius"] = thinknode.value(0.0+
-    args["organs"] = thinknode.value(ap_params.organs) +
-    args["half_planes"] = thinknode.value(ap_params.half_planes) +
-    args["corner_planes"] = thinknode.value(ap_params.corner_planes) +
-    args["centerlines"] = thinknode.value(ap_params.centerlines) +
-    args["overrides"] = thinknode.value(ap_params.overrides) +
-    args["downstream_edge"] = thinknode.value(250.5+
- +
-    return \ +
-        thinknode.function("dosimetry", "compute_aperture", +
-            [ +
-                thinknode.structure_named_type("rt_types", "aperture_creation_params", args) +
-            ])+
  
 beam_geometry = \ beam_geometry = \
 ... ...
 +
 +# Get degrader geometry as calculation result
 +degrade_geom = \
 +    thinknode.function(iam["account_name"], "dosimetry", "make_shifter", 
 +        [
 +            thinknode.value(18), # thickness
 +            thinknode.value("mm"), # units
 +            thinknode.value(200) # downstream edge
 +        ])
 +res_geom = thinknode.do_calculation(iam, degrade_geom, True)
 +degrader = \
 +    thinknode.function(iam["account_name"], "dosimetry", "make_degrader", 
 +        [
 +            thinknode.value(res_geom),
 +            thinknode.reference("56030a9500c036a0c6393f984b25e303") # Material spec from ISS
 +        ])
 +proton_degr = thinknode.do_calculation(iam, degrader)
  
 # Call compute_sobp_pb_dose2 # Call compute_sobp_pb_dose2
Line 379: Line 202:
     thinknode.function("dosimetry", "compute_sobp_pb_dose2",     thinknode.function("dosimetry", "compute_sobp_pb_dose2",
         [         [
-            make_water_phantom([-100, -100, -100], [200, 200, 200], [2, 2, 2]), #stopping_power_image+            dosimetry.make_image_3d(iam, [-100, -100, -100], [200, 200, 200], [2, 2, 2], 1), #stopping_power_image
             thinknode.value(make_dose_points(181)), # dose_points             thinknode.value(make_dose_points(181)), # dose_points
             beam_geometry, #beam_geometry             beam_geometry, #beam_geometry
-            make_grid([-75, -75], [150, 150], [2, 2]), # bixel_grid+            dosimetry.make_grid(iam, [-75, -75], [150, 150], [2, 2]), # bixel_grid
             make_layers(2270.0, 152.0, 38.0),             make_layers(2270.0, 152.0, 38.0),
             compute_aperture(), # aperture based on targets             compute_aperture(), # aperture based on targets
Line 389: Line 212:
                  
 # Perform calculation # Perform calculation
-res = thinknode.do_calculation(iam, dose_calc, id+res = thinknode.do_calculation(iam, dose_calc) 
-dl.data("Calculation Result: ", res.text)+dl.data("Calculation Result: ", res)
 </code> </code>
 ===== Python: decimal Libraries ===== ===== Python: decimal Libraries =====
Line 396: Line 219:
 ==== rt_types ==== ==== rt_types ====
  
-The //rt_types// module is a reconstruction of astroid manifest types in python class format. This includes interdependencies between types (e.g. the class "aperture_creation_params.view" requires the class "multiple_source_view").+The //rt_types// module is a reconstruction of all astroid types in python class format. This includes interdependencies between types (e.g. the class "polyset" requires the class "polygon2").
  
-Each data type detailed in the [[http://docs.apps.dotdecimal.com|Dosimetry Manifest Guide]] has a corresponding class in this python module. +Each data type detailed in the [[http://docs.apps.dotdecimal.com|astroid Manifest Guide]] has a corresponding class in this python module. 
  
- +Below you will see snippet from the rt_types module that shows the class for the //polyset// rt_type along with its default initialization, //expand_data// and //from_json// functions.
-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 initializations and //.out// function. +
-  * **Interdependence:** When dosimetry data types are constructed of other or multiple dosimetry typesthey will be constructed as such in each class as displayed by the //view// parameter of the //aperture_creation_params// in this example. The [[dosimetry:userguide:thinknode#sobp_dose_calculation|sobp dose calculation]] sample python script provides an example of this usage in actual practice. +
-  * **//out// function:** Each class's //.out// function provides an ordered dictionary of each of the values in the class. This is explicitly an ordered dictionary since when calling a function in a calculation request, the order of the values provided matters if constructing the request by thinknode value type.+
  
 <code python> <code python>
-class aperture_creation_params(object):+class polygon2(object):
  
  #Initialize  #Initialize
  def __init__(self):  def __init__(self):
- self.targets []  + blob blob_type() 
- self.target_margin 0.0  + self.vertices blob.toStr()
- 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['vertices'] = parse_bytes_2d(base64.b64decode(self.vertices['blob'])) 
- for x in self.targets+ return data 
- s = triangle_mesh()+ 
 + def from_json(self, jdict): 
 + for k, v in jdict.items(): 
 + if hasattr(self,k): 
 + setattr(self, k, v) 
 + 
 +class polyset(object): 
 + 
 + #Initialize 
 + 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['targets'] = target + data['polygons'] = polygon 
- data['target_margin'] = self.target_margin + hole = [] 
- data['view'] = self.view.expand_data() + for x in self.holes
- data['mill_radius'] = self.mill_radius + 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['organs'] = organ + data['holes'] = hole
- half_plane = [] +
- for x in self.half_planes: +
- s = aperture_half_plane() +
- s.from_json(x) +
- half_plane.append(s.expand_data()) +
- data['half_planes'] = half_plane +
- corner_plane = [] +
- for x in self.corner_planes: +
- s = aperture_corner_plane() +
- s.from_json(x) +
- corner_plane.append(s.expand_data()) +
- data['corner_planes'] = corner_plane +
- centerline = [] +
- for x in self.centerlines: +
- s = aperture_centerline() +
- s.from_json(x) +
- centerline.append(s.expand_data()) +
- data['centerlines'] = centerline +
- override = [] +
- for x in self.overrides: +
- s = aperture_manual_override() +
- s.from_json(x) +
- override.append(s.expand_data()) +
- data['overrides'] = override +
- data['downstream_edge'] = self.downstream_edge+
  return data  return data
  
Line 468: Line 269:
  for k, v in jdict.items():  for k, v in jdict.items():
  if hasattr(self,k):  if hasattr(self,k):
- if == 'view'+ setattr(self, k, v) 
- self.view.from_json(v+</code> 
- else+ 
- setattr(selfkv)+  * **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 //polygons// parameter of the //polyset// in the above example. 
 +  * **//expand_data// function:** Each class's //expand_data// function returns a python dictionary containing each of the values in the class, with all data values expanded out to remove compression or other encodings (i.eproviding results in a format more useful for send to other applications or for human-readability). 
 +  * **//from_json// function:** Each class's //from_json// function provides a method to turn a raw json string (e.g. a result from a thinknode calculation or ISS objectinto an rt_type data type. Proper use is to first construct an empty class instance, then to call the //from_json// method on that instance, passing in the desired json data string.  
 + 
 +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'dicom'dose_id)) 
 + 
 +    img = rt_types.image_3d() 
 +    img.from_json(img_data) 
 +    img2 = img.expand_data() 
 + 
 +    vtk.write_vtk_image3('E:/dicom/dose.vtk', img2)
 </code> </code>
 ==== thinknode_worker ==== ==== thinknode_worker ====
  
-The //thinknode_worker// module is the main work horse for communication with the dosimetry app and thinknode. The module will handle authentication, posting objects to ISS, creating most of the common calculation request structures, and posting the calculation request.+The //thinknode_worker// module is the main work horse for communication with the astroid app and thinknode. The module will handle authentication, posting objects to ISS, creating most of the common calculation request structures, and posting the calculation request.
  
-Refer to the [[https://github.com/dotdecimal/astroid-script-library|.decimal GitHub repository]] for the complete module. Below are a few of the more common thinknode http worker and their intended usages:+Refer to the [[https://github.com/dotdecimal/astroid-script-library|.decimal GitHub repository]] for the complete module. Below are a few of the more common thinknode_worker functions and their intended usages:
  
 <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 for the current iam configuration+# 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 api+# Send calculation request to thinknode and wait for the calculation to perform. Caches locally calculation results so if the same  
 +# 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: True = returns calculation result; False = returns calculation id +#   param return_data: When True the data object will be returned, when false the thinknode id for the object will be returned 
-def do_calculation(config, json_data, return_data=True):+#   param return_error: When False the script will exit when error is found, when True the sciprt will return the error 
 +def do_calculation(config, json_data, return_data=True, return_error=False):
  
-# Post immutable object to ISS+# Post immutable named_type 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 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 = '/iss/named/' + config["account_name"] + '/rt_types' + '/' + obj_name 
 +    return post_immutable(config, app_name, json_data, scope)
  
 # 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, obj_id):+def get_immutable(config, app_name, obj_id):
  
  
 </code> </code>
  
-==== decimal_logging ====+==== 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. 
  
-The //decimal_logging// module provides formatted and detailed output window and file logging+Refer to the [[https://github.com/dotdecimal/astroid-script-library|.decimal GitHub repository]] for the complete module. Some basic examples of provided functionality are:
  
-The following settings are available in the decimal_logging.py file: +  - Aperture creation (using structures/beams or basic geometric) 
-**display_timestamps: ** display timestamps in the output window/logfile +  - Dose comparison 
-**display_types: ** display message types (e.g. debug, data, alert) in the output window/logfile +  - Grid creation 
-**log_file: ** sets the logfile name and location+  - Image creation 
 +  - PBS Spot functions
  
-The following image shows the logging settings for each message type as: 
-  - Timestamps = //True//; Types = //True// 
-  - Timestamps = //False//; Types = //True// 
-  - Timestamps = //False//; Types = //False// 
  
-{{ dosimetry:userguide:decimal_logging_example.png |}} +==== vtk_worker ==== 
-====== Node.js ======+The VTK worker provides a means to write out common rt_types to a vtk file format ([[http://www.vtk.org/|The Visualization TooKit]]) that can be visualized in [[http://www.paraview.org/|Paraview]]. It's most useful for displaying and post-processing image, mesh, and other primitive object data types.
  
-The following section contains examples using node.js and (if applicable) the specified modules. These examples are for a high level approach to encoding and decoding the blob data that is part of the Dosimetry App calculation request.+Below is an example of turning a dose image_3d into a vtk file for visualization in Paraview:
  
-**Base64 Blob Format**+<code python> 
 +def dose_to_vtk(dose_id): 
 +    img_data = json.loads(thinknode.get_immutable(iam, 'dicom', dose_id))
  
-The blob returned by a calculation request is formatted as such:+    img = rt_types.image_3d() 
 +    img.from_json(img_data) 
 +    img2 = img.expand_data()
  
-<code cpp> +    vtk.write_vtk_image3('E:/dicom/dose.vtk', img2) 
-// value_type enum definitions +</code>
-// Nil = 0; +
-// Boolean = 1; +
-// Number = 2; +
-// String = 3; +
-// Blob = 4; +
-// List = 5; +
-// Record = 6;+
  
-// For value_types nil, boolean, number, string +==== decimal_logging ====
-// <uint32 value_type enum (4 bytes)><data>+
  
-// For value_types blob, list, record +The //decimal_logging// module provides formatted and detailed output window messages and file logging. 
-// <uint31 value_type enum (4 bytes)><size of each data (8 bytes)><data> +
-</code>+
  
-===== NodeDecrypt Base64 Blob Data =====+The following settings are available in the decimal_logging.py file: 
 +**display_timestamps: ** display timestamps in the output window/logfile 
 +**display_types: ** display message types (e.g. debug, data, alert) in the output window/logfile 
 +**log_file: ** sets the logfile name and location
  
-The following example shows , using node.js, how to decode the base64 encoded data returned by a calculation request.+=== Debugging ===
  
-<code javascript> +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 offbut it can be turned on as needed.
-// The below base64string is a blob array with the values [ -25, -25, 25, -25, 25, 25, -2525 ] +
-var b64string = "CF2Hl0z_eJxjYWBgcGBABpYH0GgHHHwMcQDM7AYN"; +
  
-// The below base64string is a number set to the value 25.1 +=== Other Flags ===
-//var b64string "NztmHgz_eJxjYmBgmDUTCCQtHQATFwOT";       +
  
-var buf = new Buffer(b64string, 'base64'); 
  
-var zlib require('zlib');+The following image shows the logging settings for each message type as: 
 +  - Timestamps //True//Types = //True// 
 +  - Timestamps = //False//; Types = //True// 
 +  - Timestamps = //False//; Types = //False//
  
-function read_base_255_number(buf, offset) { +{{ dosimetry:userguide:decimal_logging_example.png |}}
-    var n = 0; +
-    var s = 0; +
-    while (offset < buf.length) { +
-        var digit = buf[offset]; +
-        var value = buf.readUInt8(offset); +
-        offset++; +
-        s++; +
-        if (digit.toString(16) === 'ff') { +
-            break; +
-        } +
-        n = n * 255; +
-        n += value; +
-    } +
-    return [s, n]; +
-}+
  
-var size read_base_255_number(buf, 4);+=== File Logging ===
  
-zlib.unzip(buf.slice(4 + size[0]), function (err, data) { +The decimal_logging library also provides simple file loggingThe //log_file// variable at the top of the library sets the log fileBy using any of the following functionsyou can easily log data to the specified file:
-    if (err) { +
-        throw err +
-    } +
-    var value_type = data.readUInt32LE(0);+
  
-    // Number +  * log(message
-    if (value_type === 2{ +  * log_debug_data(message,data) 
-        console.log("DOUBLE", data.readDoubleLE(4)); +  * log_data(data)
-    }  +
-    // Blob +
-    else if (value_type === 4) { +
-        // Read size here +
-        var values = []; +
-        for (var i = 12; i < data.length; i+=8+
-            values.push(data.readDoubleLE(i)); +
-        } +
-        console.log(values); // Outputs: [ -25, -25, 25, -25, 25, 25, -25, 25 ] +
-    } +
-}); +
- +
-</code>+
  
 ---- ----
dosimetry/userguide/thinknode.1436532625.txt.gz · Last modified: 2021/07/29 18:21 (external edit)