Como refuerzo de los resultados experimentales, realizamos una serie de simu- laciones de Monte Carlo correspondientes a los experimentos usando CUDAMCFL. La geometría del medio y la inclusión, así como sus propiedades ópticas, son análo- gas a las usadas para los experimentos previos.
Se simularon dos casos: fantoma sin cobertura, y fantoma con vidrio más cre- ma. Para este último, la simulación se construyó usando un medio de dos capas: fantoma y vidrio, suponiendo que el IM es suficientemente bueno.
La Figura 6.18 muestra el resultado de las simulaciones, comparadas con el caso experimental del fantoma sin cobertura. Se puede ver que, más allá de errores experimentales, MC concuerda adecuadamente con los experimentos.
Modulación normali
zada
Posición angular ɑ
j[Grad.]
Fig. 6.18: Modulaciones simuladas para diferentes configuraciones de la interfaz, y dife- rentes posiciones de la inclusión.
Parte IV
7
Conclusiones y trabajo futuro
„
Contempla cada camino de cerca, entonces hazte esta pregunta crucial: ¿me lleva el corazón por esta ruta? Si lo hace, entonces el camino es bueno. Si no es así, es inútil.—Carlos Castaneda
Las enseñanzas de Don Juan
El objetivo planteado al inicio del Trabajo Doctoral que se expone en la pre- sente Tesis, fue avanzar en el estudio de la ciencia necesaria para el desarrollo de un sistema de diagnóstico por imágenes que haga uso de radiación NIR mediante reflectancia difusa de campo completo valiéndose, además, de marcadores fluores- centes.
Este trabajo se focalizó entonces en el estudio de la formación de imágenes de inclusiones inmersas en medios turbios utilizando fuentes de onda continua y geometría de reflectancia. El objetivo mediato es proveer una técnica que permita realizar mamografías ópticas que utilizan radiación no ionizante, y maximizando el confort del paciente. El precio que se paga por ello es la pérdida de resolución 3D. Sin embargo, la incorporación de un agente fluorescente permite mejorar la discriminación de lesiones, sobre todo si se considera la farmacocinética de algunas moléculas fluorescentes como la ICG.
Si bien el marco conceptual del transporte de radiación NIR en medios biológi- cos estaba muy bien desarrollado y ya había sido aplicado a un número de técnicas diagnósticas más o menos complejas, la aquí propuesta no había sido objeto de mucha atención a pesar de contar con características que la hacen ventajosa en una variedad de situaciones. Entre otras ventajas, requiere equipamiento sencillo y barato (incluso comparado con otras técnicas basadas en radiación NIR) y el proce- samiento de los datos no resulta necesariamente costoso computacionalmente.
En esta línea, luego de hacer un repaso de los conceptos y términos necesa- rios para afrontar la lectura y compresión del resto del trabajo en el Capítulo 1, se presentó la idea y principios básicos de la técnica propuesta, de la forma que luego dio inicio a la investigación subsiguiente. La misma se puede resumir en dos partes: formulación y estudio de la propuesta general, junto a la descripción de su configuración experimental y de los efectos de posibles inclusiones absorbentes y/o
fluorescentes por sobre la medición externa; y un proceso de normalización que realce estos últimos efectos, dotando de practicidad concreta a la propuesta.
Dicha normalización, descripta en la Sección 2.1 es imprescindible para la lo- calización de la lesiones y la construcción de una imagen que pueda servir para un diagnóstico directo. El procedimiento propuesto es sencillo pero innovador. Se basa en la toma de múltiples imágenes desde diferentes perspectivas que permiten construir una muy buena aproximación al fondo homogéneo necesario para norma- lizar las medidas, sin necesidad de aproximaciones o inferencias a priori sobre el medio. Esta forma de generar la imagen de referencia también ayuda a minimizar errores experimentales (efectos de iluminación esférica, aberraciones del sistema de medición, fuentes de luz indeseadas, etcétera) que puedan afectar el resultado final.
Una vez formada la idea básica, se avanzó en su caracterización y estudio de- tallado. Prontamente, se hizo evidente que algunas de las herramientas necesarias aún no estaban disponibles. En consecuencia, una porción muy importante del tra- bajo doctoral se enfocó en el estudio detallado del modelo teórico, junto a sus límites de validez, y en el desarrollo e implementación de un algoritmo de Monte Carlo con la capacidad de simular los fundamentos de la propuesta.
Se eligió profundizar en los códigos Monte Carlo como herramienta para poder tener acceso a geometrías más diversas con la posibilidad de poder simular medios con inclusiones de forma y propiedades ópticas arbitrarias.
El algoritmo desarrollado con ese propósito, presentado en la Sección 4.3 y llamado CUDAMCFL, constituye un aporte de suma importancia a la comunidad científica ya que no existía ningún código que permita simular medios absorben- tes y fluorescentes de complejidad arbitraria mediante Monte Carlo. Su desarrollo requirió una gran cantidad de horas de investigación y programación así como de validación y optimización.
El resultado fue un software validado por la comunidad científica y distribuido bajo licencia de software libre, de gran flexibilidad. El mismo constituye una herra- mienta muy valiosa para la caracterización de la técnica de reflectancia difusa en configuraciones imposibles de realizar experimentalmente y con completo control de las diferentes variables en juego. En el presente trabajo se describió en detalle el trabajo realizado en el desarrollo, prueba y validación de CUDAMCFL y se muestra un ejemplo de una simulación importante para la caracterización de la técnica de reflectancia difusa que no era posible con los códigos previos.
Presentada la propuesta y las herramientas desarrolladas para su investigación, se mostraron seguidamente, en el Capítulo 5, experimentos de validación de la téc- nica. Los mismos fueron realizados en fantomas que recrean las propiedades ópticas
esperables en casos de interés clínico. El objetivo fue verificar que es posible detec- tar, localizar, y caracterizar inicialmente la presencia de lesiones fluorescentes y ab- sorbentes. Se eligieron configuraciones experimentales deliberadamente complejas como prueba de estrés de la técnica. La diferencia de concentración de fluoróforos y absorbentes entre medio e inclusión, tamaño y posición de la misma, y caracte- rísticas fluorescentes del medio fueron significativamente más exigentes que la que habitualmente es encontrada en la bibliografía para otras técnicas.
Los resultados mostraron que la propuesta es viable incluso con las limitaciones técnicas de los medios de captura de imágenes y la baja eficiencia cuántica del marcador fluorescente elegido. Inclusiones de 1cm de diámetro son detectables hasta1,75cm de profundidad tanto en absorción como en fluorescencia. Además, al contar con ambas imágenes, su combinación permite mejorar la estadística y el contraste de la medición. Dado que dentro de esta “inclusión” se encontraría no sólo el tumor propiamente dicho sino también, y en especial, la vascularización que lo alimenta, es un resultado alentador para la detección de neoplasmas incipientes.
Seguidamente, con el incentivo de la validación experimental y valiéndonos de las herramientas desarrolladasad-hoc, en el Capítulo 6 se indagaron detalles más específicos necesarios para una implementación práctica de la técnica. Se presen- tó un análisis novedoso de la sensibilidad de un sistema de reflectancia difusa de campo completo, haciendo hincapié en los desafíos introducidos por el uso de una fuente puntual. Usando el modelo teórico se construyó un mapa de sensibilidad que, además de cuantificar la detectabilidad de las inclusiones, puede ser usado para incrementar la resolución de la técnica.
Con este mapa de sensibilidad, y con el objetivo de corregir las limitaciones antes mencionadas, se introdujo un nuevo protocolo de toma de imágenes y norma- lización. El mismo fue validado mediante Monte Carlo, simulando completamente el proceso tal cual podría ser aplicable en un prototipo. Así podemos mostrar que este protocolo es capaz de localizar y resolver inclusiones de variadas formas y con una sensibilidad plana en el espacio de interés.
Avanzando en la recuperación de información de la inclusión, mostramos lue- go en la Sección 6.3 un procedimiento que permite inferir una razonable aproxima- ción sobre la profundidad. Mostramos que si bien la reflectancia difusa de campo completo no llega a ser un sistema tomográfico, es posible recuperar una buena aproximación a la posición 3D de posibles lesiones. Finalmente, en la Sección 6.4 estudiamos cómo minimizar los efectos negativos de la interfaz entre el tejido a es- tudiar y el ambiente. Valiéndonos de datos experimentales y simulaciones de Monte Carlo presentamos una solución simple y económica para la implementación prácti- ca de la misma.
En resumen, como aportes de esta tesis:
Se estudiaron los límites del modelo difusivo y la transición entre el régimen balístico y el difusivo.
De desarrolló un software para la simulación por Monte Carlo del transporte difusivo de fotones en medios turbios fluorescentes con inclusiones, ofrecido en calidad de Software Libre.
Se propuso y validó experimentalmente una técnica de normalización basada en información proveniente solamente de datos de medición.
Se presentó un mecanismo para la obtención de información 3D de las lesio- nes.
Se estudiaron los efectos de la interfaz mecánica entre el tejido a estudiar y el medio para casos reales.
Los resultados obtenidos solidifican la idea de que la formación de imágenes diagnósticas usando reflectancia difusa de campo completo usando radiación NIR es un buen complemento de los métodos ya establecidos. Más allá de las ventajas radicadas en el uso de radiación NIR y que son compartidas por otras técnicas de óptica biomédica de medios turbios, la aquí presentada destaca por su relativa simplicidad y bajo costo.
Estos estudios se reflejan en cinco trabajos publicados en revistas con referato internacional [53, 16, 39, 77, 86], numerosas comunicaciones a congresos tanto nacionales como internacionales, futuras líneas de trabajo y herramientas útiles para la comunidad científica.
7.1
Trabajo futuro
Los principales resultados de los estudios realizados durante la presente Tesis un número de desafíos para trabajos futuros, así como la posibilidad de construir a partir de ellos un equipo prototipo a nivel laboratorio para decidir sobre la utilidad clínica del enfoque planteado.
En consecuencia, y como trabajo que continúe el aquí presentado, se propo- ne:
Analizar y determinar los requisitos de formación de imagen, con el objeti- vo de cuantificar las características que debe cumplir el sensor CCD/IMCC- D/sCCD a utilizar.
Desarrollar protocolos de procesamiento de imágenes que tengan en cuenta el modelo físico y los posibles requisitos clínicos.
Caracterizar las diferentes estrategias de toma de múltiples exposiciones desa- rrolladas previamente, apuntando a la construcción futura de un dispositivo automático de captura.
Estudiar el uso de diferentes agentes de contraste, como nanorods de oro, cuantificando las cantidades detectables por la técnica y evaluando formas de determinar su localización y concentración en el medio a estudiar.
Investigar el comportamiento de láseres de diferentes longitudes de onda. Los mismos podrán ser utilizados para explorar diferentes componentes biológi- cos de los tejidos (por ejemplo635nm,785nmy830nmpara la hemoglobina, 915nmpara la grasa).
Identificar y cuantificar los límites de detectabilidad y las características re- cuperables para diferentes tipos de inhomogeneidades patológicas, utilizando experimentalmente fantomas de propiedades ópticas y geometrías conocidas, como así también simulaciones que complementen las mediciones.
Finalmente, se apunta al desarrollo de un sistema prototipo que pueda, en una futura etapa, ser utilizado conjuntamente con investigadores del área de la medi- cina y la veterinaria como paso indispensable para la caracterización médica de la técnica. Dada su complejidad, naturaleza interdisciplinaria, y limitaciones de ins- trumental y presupuesto, este trabajo colaborativo quedó por fuera de los límites del presente trabajo. Es, sin embargo, requisito necesario para transferir a la socie- dad los frutos de años de trabajo en investigación básica y aplicada desarrollada por nuestro grupo de investigación y el presente plan de trabajo es un paso muy importante en esa dirección.
Parte V
8
Salida del
profiler
„
Premature optimization is the root of all evil.—Sir Tony Hoare
1 ==1363== NVPROF is profiling process 1363, command: ./cuda_fl inclusion2-v2-3d-gs1-fast.mci
2 ==1363== Profiling application: ./cuda_fl inclusion2-v2-3d-gs1-fast.mci
3 ==1363== Profiling result:
4 Time( %) Time Calls Avg Min Max Name
5 99.58 % 71.0496s 2217 32.048ms 6.3998ms 148.63ms MCd3D(MemStruct)
6 0.26 % 185.72ms 12438 14.931us 1.2480us 63.620us [CUDA memcpy DtoH]
7 0.09 % 64.028ms 6003 10.666us 2.4000us 21.121us [CUDA memset]
8 0.05 % 35.759ms 42021 850ns 512ns 8.1280us [CUDA memcpy HtoD]
9 0.02 % 16.837ms 2001 8.4140us 6.6240us 9.4410us LaunchPhoton_Global(MemStruct)
10
11 ==1363== API calls:
12 Time( %) Time Calls Avg Min Max Name
13 61.78 % 2.8e+03s 4218 661.22ms 3.4690us 26.7338s cudaThreadSynchronize
14 36.48 % 1.6e+03s 22443 73.386ms 3.8060us 26.6063s cudaMemcpy
15 1.18 % 53.2249s 32016 1.6624ms 2.9460us 26.5718s cudaMemcpyToSymbol
16 0.54 % 24.4294s 18009 1.3565ms 4.2110us 22.6391s cudaMalloc
17 0.02 % 900.31ms 18009 49.992us 3.9560us 419.35us cudaFree
18 0.00 % 75.886ms 6003 12.641us 5.2570us 111.10us cudaMemset
19 0.00 % 39.358ms 4218 9.3300us 4.8350us 38.731us cudaLaunch
20 0.00 % 2.0379ms 4218 483ns 186ns 9.1130us cudaGetLastError
21 0.00 % 1.8967ms 4218 449ns 158ns 191.31us cudaConfigureCall
22 0.00 % 1.3732ms 4218 325ns 151ns 8.8000us cudaSetupArgument
23 0.00 % 166.88us 91 1.8330us 124ns 68.760us cuDeviceGetAttribute
24 0.00 % 65.881us 1 65.881us 65.881us 65.881us cuDeviceTotalMem
25 0.00 % 22.471us 1 22.471us 22.471us 22.471us cuDeviceGetName
26 0.00 % 1.9430us 3 647ns 148ns 1.0530us cuDeviceGetCount
27 0.00 % 815ns 3 271ns 198ns 362ns cuDeviceGet
La gran mayoría del tiempo de cómputo se gasta en MCd3D, la función kernel que hace el transporte de fotones. Sin embargo es notable quecudaThreadSynchronize()
es, por mucho, la API más llamada. Esta función de CUDA es ejecutada cada vez que queremos asegurarnos que todos los hilos están sincronizados y, en CUDAMCFL, es usada al final de cada loop de la simulación de transporte “esperará” que todos los fotones terminen. Sin embargo, su importancia está sobreestimada ya que en un
dado momento, incluso cuando algunos hilos pueden estar esperando, la mayoría está corriendo.
Como el número de eventos de scattering que cada fotón va a sufrir es aleatorio y desconocido, el tiempo que cada hilo va a estar ejecutándose puede variar signi- ficativamente. En la presente versión de CUDAMCFL, cada fuente de fluorescencia (cada voxel de la matriz densidad de fotones) se trata como una nueva simulación y una llamada a cudaThreadSynchronize es usada al final de cada una. De esta manera, algo del poder de computo se desperdicia mientras los hilos más rápidos esperan a que los más lentos terminan.
9
Códigos fuente
„
Unfortunately, no one can be told what The Matrix is. You’ll have to see it for yourself.—Morpheus The Matrix
9.1
CUDAMCFL
9.1.1
Main
1 ///////////////////////////////////////////////////////////// 2 //3 // Monte Carlo simulation software for light propagation in fluorescent turbid media,
4 // accelerated by GPU (graphic processing unit).
5 // The code is based on previous work by Alerstam et al and Wang et al,
6 // with the addition of a voxelized medium without symmetries and with an
7 // inhomogeneous distribution of absorbers and fluorescent marker
8 //
9 ///////////////////////////////////////////////////////////////
10
11 /* This file is part of CUDAMCFL.
12
13 CUDAMCFL is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 CUDAMCFL is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with CUDAMCFL. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include "CUDAMCFL.h"
28 #include "cutil.h"
29 //#include <float.h> //for FLT_MAX
30 #include <limits.h>
31 #include <stdio.h>
32 #include "cuda_profiler_api.h"
33
34 __device__ __constant__ unsigned long long num_photons_dc[1];
35 __device__ __constant__ unsigned int n_layers_dc[1];
36 __device__ __constant__ unsigned int n_bulks_dc[1];
37 __device__ __constant__ unsigned int start_weight_dc[1];
38 __device__ __constant__ LayerStruct layers_dc[MAX_LAYERS];
39 __device__ __constant__ BulkStruct bulks_dc[MAX_LAYERS];
40 __device__ __constant__ DetStruct det_dc[1];
41 __device__ __constant__ IncStruct inclusion_dc[1];
42 __device__ __constant__ unsigned int ignoreAdetection_dc[1];
43 __device__ __constant__ unsigned int fhd_activated_dc[1];
44 __device__ __constant__ unsigned int bulk_method_dc[1];
45 __device__ __constant__ float xi_dc[1];
46 __device__ __constant__ float yi_dc[1];
47 __device__ __constant__ float zi_dc[1];
48 __device__ __constant__ float dir_dc[1];
49 __device__ __constant__ float esp_dc[1];
50 __device__ __constant__ unsigned int grid_size_dc[1];
51 52 #include "CUDAMCFLio.cu" 53 #include "CUDAMCFLmem.cu" 54 #include "CUDAMCFLrng.cu" 55 #include "CUDAMCFLtransport.cu" 56
57 // wrapper for device code - FHD Simulation
58 unsigned long long DoOneSimulation(SimulationStruct *simulation, unsigned long long *x,
59 unsigned int *a, double *tempfhd) {
60 MemStruct DeviceMem;
61 MemStruct HostMem;
62 unsigned int threads_active_total = 1;
63 unsigned int i, ii;
64
65 // Output matrix size
66 const int num_x = (int)(4 * (simulation->esp) * (float)simulation->grid_size);
67 const int num_y = (int)(4 * (simulation->esp) * (float)simulation->grid_size);
68 const int num_z = (int)((simulation->esp) * (float)simulation->grid_size);
69 const int fhd_size = num_x * num_y * num_z;
70
71 cudaError_t cudastat;
72 clock_t time1, time2;
73
74 // Start the clock
75 time1 = clock();
76
77 // x and a are already initialised in memory
78 HostMem.x = x;
79 HostMem.a = a;
80
82
83 InitDCMem(simulation);
84
85 dim3 dimBlock(NUM_THREADS_PER_BLOCK);
86 dim3 dimGrid(NUM_BLOCKS);
87 int blockSize; // The launch configurator returned block size
88 int minGridSize; // The minimum grid size needed to achieve the
89 // maximum occupancy for a full device launch
90 //int gridSize; // The actual grid size needed, based on input size
91
92 cudaOccupancyMaxPotentialBlockSize( &minGridSize, &blockSize,
93 MCd3D, 0, 0);
94 printf ("Grid size: %i, Block size: %i \n\n", minGridSize, blockSize);
95 96
97 LaunchPhoton_Global<<<dimGrid, dimBlock>>>(DeviceMem);
98 //LaunchPhoton_Global<<<minGridSize, blockSize>>>(DeviceMem);
99 CUDA_SAFE_CALL(cudaThreadSynchronize()); // Wait for all threads to finish
100 cudastat = cudaGetLastError(); // Check if there was an error
101 if (cudastat)
102 printf("Error code= %i, %s.\n", cudastat, cudaGetErrorString(cudastat));
103
104 i = 0;
105 while (threads_active_total > 0) {
106 i++;
107 // run the kernel
108 if (simulation->bulk_method == 1){ 109 MCd<<<dimGrid, dimBlock>>>(DeviceMem); 110 //MCd<<<minGridSize, blockSize>>>(DeviceMem); 111 112 } 113 else if (simulation->bulk_method == 2) { 114 115 MCd3D<<<dimGrid, dimBlock>>>(DeviceMem); 116 //MCd3D<<<minGridSize, blockSize>>>(DeviceMem); 117 } 118
119 CUDA_SAFE_CALL(cudaThreadSynchronize()); // Wait for all threads to finish
120 cudastat = cudaGetLastError(); // Check if there was an error
121 if (cudastat)
122 printf("Error code= %i, %s.\n", cudastat, cudaGetErrorString(cudastat));
123
124 // Copy thread_active from device to host
125 CUDA_SAFE_CALL(cudaMemcpy(HostMem.thread_active, DeviceMem.thread_active,
126 NUM_THREADS * sizeof(unsigned int),
127 cudaMemcpyDeviceToHost));
128 threads_active_total = 0;
129 for (ii = 0; ii < NUM_THREADS; ii++)
130 threads_active_total += HostMem.thread_active[ii];
131
132 CUDA_SAFE_CALL(cudaMemcpy(HostMem.num_terminated_photons,
133 DeviceMem.num_terminated_photons,
134 sizeof(unsigned long long), cudaMemcpyDeviceToHost));
135 if (i == 100)
136 printf("Estimated PHD simulation time: %.0f secs.\n\n",
137 (double)(clock() - time1) / CLOCKS_PER_SEC *
138 (double)(simulation->number_of_photons /
139 *HostMem.num_terminated_photons));
140 // if (fmod(i, 200u) == 0) printf("."); fflush(stdout);
141 if (i % 100 == 0) printf("."); fflush(stdout);
142 if (i % 2000 == 0)
143 printf("\nRun %u, %llu photons simulated\n", i,
144 *HostMem.num_terminated_photons);
145 }
146
147 CopyDeviceToHostMem(&HostMem, &DeviceMem, simulation);
148
149 time2 = clock();
150
151 printf("\nSimulation time: %.2f sec\n\n",
152 (double)(time2 - time1) / CLOCKS_PER_SEC);
153
154 printf("Writing excitation results...\n");
155 Write_Simulation_Results(&HostMem, simulation, time2-time1);
156 printf("PHD Simulation done!\n");
157
158 unsigned long long photons_finished = *HostMem.num_terminated_photons;
159
160 // Normalize and write output matrix
161 for (int xyz = 0; xyz < fhd_size; xyz++) {
162 tempfhd[xyz] = ((double)HostMem.fhd[xyz]/(0xFFFFFFFF*photons_finished));
163 }
164
165 printf ("Photons simulated: %llu\n\n", photons_finished);
166 FreeMemStructs(&HostMem, &DeviceMem);
167 return photons_finished;
168 }
169
170 // wrapper for device code - fluorescence Simulation
171 unsigned long long DoOneSimulationFl(SimulationStruct *simulation, unsigned long long *x,
172 unsigned int *a, unsigned long long *tempvoxelR, unsigned long long *tempvoxelT) {
173 MemStruct DeviceMem;
174 MemStruct HostMem;
175 unsigned int threads_active_total = 1;
176 unsigned int i, ii;
177
178 // Size of output matrix
179 const int nx2 = simulation->det.nx;
180 const int ny2 = simulation->det.ny;
182
183 cudaError_t cudastat;
184
185 // x and a are already initialised in memory
186 HostMem.x = x;
187 HostMem.a = a;
188
189 InitMemStructs(&HostMem, &DeviceMem, simulation);
190
191 InitDCMem(simulation);
192
193 dim3 dimBlock(NUM_THREADS_PER_BLOCK);
194 dim3 dimGrid(NUM_BLOCKS);
195 int blockSize; // The launch configurator returned block size
196 int minGridSize; // The minimum grid size needed to achieve the
197 // maximum occupancy for a full device launch
198 //int gridSize; // The actual grid size needed, based on input size T
199
200 cudaOccupancyMaxPotentialBlockSize( &minGridSize, &blockSize,
201 MCd, 0, 0); //TODO
202 //printf ("Grid size: %i, Block size: %i \n\n", minGridSize, blockSize);
203
204 LaunchPhoton_Global<<<dimGrid, dimBlock>>>(DeviceMem);
205 //LaunchPhoton_Global<<<minGridSize, blockSize>>>(DeviceMem);
206
207 CUDA_SAFE_CALL(cudaThreadSynchronize()); // Wait for all threads to finish
208 cudastat = cudaGetLastError(); // Check if there was an error
209 if (cudastat)
210 printf("Error code= %i, %s.\n", cudastat, cudaGetErrorString(cudastat));
211
212 i = 0;
213 while (threads_active_total > 0) {
214 i++;
215 // run the kernel
216 if (simulation->bulk_method == 1){ 217 MCd<<<dimGrid, dimBlock>>>(DeviceMem); 218 //MCd<<<minGridSize, blockSize>>>(DeviceMem); 219 220 } 221 else if (simulation->bulk_method == 2) { 222 MCd3D<<<dimGrid, dimBlock>>>(DeviceMem); 223 //MCd3D<<<minGridSize, blockSize>>>(DeviceMem); 224 } 225
226 CUDA_SAFE_CALL(cudaThreadSynchronize()); // Wait for all threads to finish
227 cudastat = cudaGetLastError(); // Check if there was an error