Skip to content

Commit ab5f36b

Browse files
authored
Fix for Bortfeld model (#1199)
* compilation * fixes
1 parent adcd3a9 commit ab5f36b

File tree

2 files changed

+108
-88
lines changed

2 files changed

+108
-88
lines changed

recompile_wasm.sh

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/bash
2+
3+
# Define key paths
4+
WORKDIR="/workspaces/web/library/distributions/JavaScript"
5+
OUTPUT_DIR="$WORKDIR/output"
6+
DEST_DIR1="/workspaces/web/src"
7+
DEST_DIR2="$DEST_DIR1/static/js"
8+
9+
# Define GSL paths
10+
GSL_INCLUDE_DIRS="$HOME/usr/include"
11+
GSL_LIBRARY="$HOME/usr/lib/libgsl.a"
12+
GSL_CBLAS_LIBRARY="$HOME/usr/lib/libgslcblas.a"
13+
14+
# Print status
15+
echo "Changing directory to: $WORKDIR"
16+
17+
# Navigate to working directory and compile
18+
echo "Compiling JavaScript distribution..."
19+
cd "$WORKDIR" && GSL_INCLUDE_DIRS=$GSL_INCLUDE_DIRS GSL_LIBRARY=$GSL_LIBRARY GSL_CBLAS_LIBRARY=$GSL_CBLAS_LIBRARY ./compile_to_js.sh
20+
21+
echo "Compilation complete. Copying output files..."
22+
23+
# Copy compiled files to destination directories
24+
echo "Copying libat.js to $DEST_DIR1"
25+
cp "$OUTPUT_DIR/libat.js" "$DEST_DIR1"
26+
echo "Copying libat.js to $DEST_DIR2"
27+
cp "$OUTPUT_DIR/libat.js" "$DEST_DIR2"
28+
echo "Copying libat.wasm to $DEST_DIR1"
29+
cp "$OUTPUT_DIR/libat.wasm" "$DEST_DIR1"
30+
echo "Copying libat.wasm to $DEST_DIR2"
31+
cp "$OUTPUT_DIR/libat.wasm" "$DEST_DIR2"
32+
33+
echo "All files copied successfully."
+75-88
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,80 @@
11
export default function AT_dose_Bortfeld_Gy(parameters) {
2-
let at_dose_bortfeld_gy_multi = Module.cwrap('AT_dose_Bortfeld_Gy_multi', 'null', ['number', 'array', 'number', 'number', 'number', 'number', 'number', 'number']);
3-
let at_dose_bortfeld_gy_single = Module.cwrap('AT_dose_Bortfeld_Gy_single', 'number', ['number', 'number', 'number', 'number', 'number', 'number']);
4-
5-
let at_range_bortfeld_cm = Module.cwrap('AT_range_Bortfeld_cm', 'number', ['number', 'number', 'number', 'number', 'number', 'undefined']);
6-
let at_fwhm_bortfeld_cm = Module.cwrap('AT_fwhm_Bortfeld_cm', 'number', ['number', 'number', 'number', 'number', 'number', 'undefined']);
7-
let at_max_plateau_bortfeld = Module.cwrap('AT_max_plateau_Bortfeld', 'number', ['number', 'number', 'number', 'number', 'number', 'undefined']);
8-
9-
10-
/*********************STANDARD PARAMETER*************************/
11-
if(typeof parameters.n === "undefined"){
12-
alert("MESSAGE TO DEVELOPER: NO PARAMETER n IN OBJECT PASSED TO THIS FUNCTIONS");
13-
return "error";
2+
// Validate required parameters
3+
if (!parameters) {
4+
throw new Error("Parameters object is required.");
145
}
15-
let n = parameters.n;
16-
17-
/*********************INPUT ARRAY********************************/
18-
if(typeof parameters.z_cm === "undefined"){
19-
alert("MESSAGE TO DEVELOPER: NO PARAMETER z_cm IN OBJECT PASSED TO THIS FUNCTIONS");
20-
return "error";
6+
const requiredParams = ['n', 'z_cm', 'E_MeV', 'entrance_dose_Gy', 'sigma_E_MeV', 'material_no', 'eps'];
7+
for (const param of requiredParams) {
8+
if (typeof parameters[param] === "undefined") {
9+
throw new Error(`Missing parameter: ${param}`);
10+
}
2111
}
22-
let z_cm = parameters.z_cm;
23-
let z_cmData = new Float64Array(z_cm);
24-
let z_cmDataBytesNumber = z_cmData.length * z_cmData.BYTES_PER_ELEMENT;
25-
let z_cmDataPointer = Module._malloc(z_cmDataBytesNumber);
26-
let z_cmHeap = new Uint8Array(Module.HEAPF64.buffer, z_cmDataPointer, z_cmDataBytesNumber);
27-
z_cmHeap.set(new Uint8Array(z_cmData.buffer));
28-
29-
/*********************STANDARD PARAMETER*************************/
30-
if(typeof parameters.E_MeV === "undefined"){
31-
alert("MESSAGE TO DEVELOPER: NO PARAMETER E_MeV IN OBJECT PASSED TO THIS FUNCTIONS");
32-
return "error";
33-
}
34-
let E_MeV = parameters.E_MeV;
35-
36-
/*********************STANDARD PARAMETER*************************/
37-
if(typeof parameters.entrance_dose_Gy === "undefined"){
38-
alert("MESSAGE TO DEVELOPER: NO PARAMETER entrance_dose_Gy IN OBJECT PASSED TO THIS FUNCTIONS");
39-
return "error";
40-
}
41-
let entrance_dose_Gy = parameters.entrance_dose_Gy;
42-
43-
/*********************STANDARD PARAMETER*************************/
44-
if(typeof parameters.sigma_E_MeV === "undefined"){
45-
alert("MESSAGE TO DEVELOPER: NO PARAMETER sigma_E_MeV IN OBJECT PASSED TO THIS FUNCTIONS");
46-
return "error";
12+
13+
const n = parameters.n;
14+
const z_cm = parameters.z_cm;
15+
if (!Array.isArray(z_cm)) {
16+
throw new Error("Parameter 'z_cm' must be an array.");
4717
}
48-
let sigma_E_MeV = parameters.sigma_E_MeV;
49-
50-
/*********************STANDARD PARAMETER*************************/
51-
if(typeof parameters.material_no === "undefined"){
52-
alert("MESSAGE TO DEVELOPER: NO PARAMETER material_no IN OBJECT PASSED TO THIS FUNCTIONS");
53-
return "error";
54-
}
55-
let material_no = parameters.material_no;
56-
57-
/*********************STANDARD PARAMETER*************************/
58-
if(typeof parameters.eps === "undefined"){
59-
alert("MESSAGE TO DEVELOPER: NO PARAMETER eps IN OBJECT PASSED TO THIS FUNCTIONS");
60-
return "error";
18+
const E_MeV = parameters.E_MeV;
19+
const entrance_dose_Gy = parameters.entrance_dose_Gy;
20+
const sigma_E_MeV = parameters.sigma_E_MeV;
21+
const material_no = parameters.material_no;
22+
const eps = parameters.eps;
23+
24+
// Setup wasm functions
25+
// Note: Change second argument from 'array' to 'number'
26+
const at_dose_bortfeld_gy_multi = Module.cwrap('AT_dose_Bortfeld_Gy_multi', null,
27+
['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);
28+
const at_dose_bortfeld_gy_single = Module.cwrap('AT_dose_Bortfeld_Gy_single', 'number',
29+
['number', 'number', 'number', 'number', 'number', 'number']);
30+
const at_range_bortfeld_cm = Module.cwrap('AT_range_Bortfeld_cm', 'number',
31+
['number', 'number', 'number', 'number', 'number', 'undefined']);
32+
const at_fwhm_bortfeld_cm = Module.cwrap('AT_fwhm_Bortfeld_cm', 'number',
33+
['number', 'number', 'number', 'number']);
34+
const at_max_plateau_bortfeld = Module.cwrap('AT_max_plateau_Bortfeld', 'number',
35+
['number', 'number', 'number', 'number']);
36+
37+
// Allocate memory for the input array z_cm and the output array dose_Gy
38+
const z_cmData = new Float64Array(z_cm);
39+
const z_cmDataBytesNumber = z_cmData.length * z_cmData.BYTES_PER_ELEMENT;
40+
const z_cmDataPointer = Module._malloc(z_cmDataBytesNumber);
41+
const z_cmHeap = new Uint8Array(Module.HEAPF64.buffer, z_cmDataPointer, z_cmDataBytesNumber);
42+
z_cmHeap.set(new Uint8Array(z_cmData.buffer));
43+
44+
// Create output array with proper size
45+
const dose_GyReturnData = new Float64Array(n);
46+
const dose_GyReturnDataBytesNumber = dose_GyReturnData.length * dose_GyReturnData.BYTES_PER_ELEMENT;
47+
const dose_GyReturnDataPointer = Module._malloc(dose_GyReturnDataBytesNumber);
48+
// const dose_GyReturnHeap = new Uint8Array(Module.HEAPF64.buffer, dose_GyReturnDataPointer, dose_GyReturnDataBytesNumber);
49+
50+
try {
51+
// Calculate entrance dose for unit fluence at depth z_cm = 0
52+
const entrance_dose_for_unit_fluence_Gy = at_dose_bortfeld_gy_single(0.0, 1.0, E_MeV, sigma_E_MeV, material_no, eps);
53+
const fluence_cm2 = entrance_dose_Gy / entrance_dose_for_unit_fluence_Gy;
54+
55+
// Compute dose over all depths: pass pointer instead of typed array view
56+
at_dose_bortfeld_gy_multi(n, z_cmDataPointer, fluence_cm2, E_MeV, sigma_E_MeV, material_no, eps, dose_GyReturnDataPointer);
57+
const resultFromArray = new Float64Array(Module.HEAPF64.buffer, dose_GyReturnDataPointer, n);
58+
59+
// Compute additional metadata
60+
const dose_drop = -1;
61+
const search_direction = 1;
62+
const range_cm = at_range_bortfeld_cm(E_MeV, sigma_E_MeV, material_no, eps, dose_drop, search_direction);
63+
const fwhm_cm = at_fwhm_bortfeld_cm(E_MeV, sigma_E_MeV, material_no, eps);
64+
const max_plateau = at_max_plateau_bortfeld(E_MeV, sigma_E_MeV, material_no, eps);
65+
66+
return {
67+
data: Array.from(resultFromArray),
68+
metadata: {
69+
range_cm: range_cm,
70+
fwhm_cm: fwhm_cm,
71+
max_plateau: max_plateau
72+
}
73+
};
74+
} finally {
75+
// Free allocated memory to avoid memory leaks
76+
// Module._free(z_cmDataPointer);
77+
// Module._free(dose_GyReturnDataPointer);
6178
}
62-
let eps = parameters.eps;
63-
64-
/*********************OUTPUT ARRAY*******************************/
65-
let dose_GyReturnData = new Float64Array(new Array(n));
66-
let dose_GyReturnDataBytesNumber = dose_GyReturnData.length * dose_GyReturnData.BYTES_PER_ELEMENT;
67-
let dose_GyReturnDataPointer = Module._malloc(dose_GyReturnDataBytesNumber);
68-
let dose_GyReturnHeap = new Uint8Array(Module.HEAPF64.buffer, dose_GyReturnDataPointer, dose_GyReturnDataBytesNumber);
69-
70-
/*********************CALL FUNCTION******************************/
71-
72-
// dose calculated at depth z_cm = 0 (entrance) and fluence_cm = 1 (unit fluence)
73-
let entrance_dose_for_unit_fluence_Gy = at_dose_bortfeld_gy_single(0.0, 1.0, E_MeV, sigma_E_MeV, material_no, eps);
74-
let fluence_cm2 = entrance_dose_Gy / entrance_dose_for_unit_fluence_Gy;
75-
76-
let result = at_dose_bortfeld_gy_multi(n, z_cmHeap, fluence_cm2, E_MeV, sigma_E_MeV, material_no, eps, dose_GyReturnHeap.byteOffset);
77-
let resultFromArray = new Float64Array(dose_GyReturnHeap.buffer, dose_GyReturnHeap.byteOffset, dose_GyReturnData.length);
78-
79-
/*********************STANDARD PARAMETER*************************/
80-
let dose_drop = -1;
81-
82-
/*********************STANDARD PARAMETER*************************/
83-
let search_direction = 1;
84-
85-
/*********************CALL FUNCTION******************************/
86-
let range_cm = at_range_bortfeld_cm(E_MeV, sigma_E_MeV, material_no, eps, dose_drop, search_direction);
87-
let fwhm_cm = at_fwhm_bortfeld_cm(E_MeV, sigma_E_MeV, material_no, eps, dose_drop, search_direction);
88-
let max_plateau = at_max_plateau_bortfeld(E_MeV, sigma_E_MeV, material_no, eps, dose_drop, search_direction);
89-
90-
let combined ={'data' : [].slice.call(resultFromArray) , 'metadata' : [range_cm,fwhm_cm,max_plateau] };
91-
92-
return combined;
93-
}
79+
}
80+

0 commit comments

Comments
 (0)