ASCOT5
Loading...
Searching...
No Matches
mccc_wiener.c
Go to the documentation of this file.
1
9#include <stdlib.h>
10#include <stdio.h>
11#include <math.h>
12#include "../../math.h"
13#include "../../ascot5.h"
14#include "../../consts.h"
15#include "../../error.h"
16#include "mccc_wiener.h"
17
19#ifdef _OPENACC
20const int MCCC_EMPTY = -1;
21#pragma acc declare copyin(MCCC_EMPTY)
22#elif defined(_OPENMP)
23DECLARE_TARGET
24const int MCCC_EMPTY = -1;
25DECLARE_TARGET_END
26#else
27const int MCCC_EMPTY = -1;
28#endif
29
37
38 /* Initialize position instances indicating all slots are empty */
39 for(int i=0; i<MCCC_NSLOTS; i++){
40 w->nextslot[i] = MCCC_EMPTY;
41 }
42
43 /* W(t_0) = 0 by the definition of the Wiener process */
44 w->nextslot[0] = 0;
45 w->time[0] = initime;
46 for(int i = 0; i < MCCC_NDIM; i++){
47 w->wiener[i] = 0.0;
48 }
49}
50
57void mccc_wiener_offload(mccc_wienarr* w, int mrk_array_size) {
58 GPU_MAP_TO_DEVICE(w[0:mrk_array_size])
59 for (int i = 0; i < mrk_array_size; i++) {
60 GPU_MAP_TO_DEVICE( w[i].nextslot[0:MCCC_NSLOTS] )
61 GPU_MAP_TO_DEVICE( w[i].time[0:MCCC_NSLOTS] )
62 GPU_MAP_TO_DEVICE( w[i].wiener[0:MCCC_NDIM*MCCC_NSLOTS] )
63 }
64
65}
66
73void mccc_wiener_onload(mccc_wienarr* w, int mrk_array_size) {
74 for (int i = 0; i < mrk_array_size; i++) {
75 GPU_UPDATE_FROM_DEVICE( w[i].nextslot )
76 GPU_UPDATE_FROM_DEVICE( w[i].time )
77 GPU_UPDATE_FROM_DEVICE( w[i].wiener )
78 }
79}
80
96a5err mccc_wiener_generate(mccc_wienarr* w, real t, int* windex, real* rand5){
97 a5err err = 0;
98 int eidx; /* Helper variables */
99 int im, ip; /* Indices of the Wiener processes for which tm < t < tp */
100
101 windex[0] = -1;
102 im = 0;
103 ip = -1; /* There isn't necessarily a Wiener process tp > t */
104
105 /* Find im and ip */
106 int idx = 0, breakloop = 0;
107 for(int i=0; i<MCCC_NSLOTS; i++){
108 if(!breakloop) {
109 if(w->nextslot[idx] == idx){
110 /* Reached last process. Break loop */
111 breakloop = 1;
112 }
113 if(w->time[idx] == t) {
114 /* Process already exists */
115 windex[0] = idx;
116 breakloop = 1;
117 }
118 else {
119 if(w->time[idx] < t ) {
120 /* Process i for which t_i < t */
121 im = idx;
122 }
123 if(w->time[w->nextslot[idx]] > t) {
124 /* Process i for which t_i > t */
125 ip = w->nextslot[idx];
126 breakloop = 1;
127 }
128 }
129 idx = w->nextslot[idx];
130 }
131 }
132
133 if(windex[0] == -1) {
134 /* Find an empty slot for the next process */
135 eidx = 0;
136 for(int i=0; i<MCCC_NSLOTS; i++){
137 if( w->nextslot[i] == MCCC_EMPTY){
138 eidx = i;
139 i = MCCC_NSLOTS;
140 }
141 }
142 if(eidx == 0){
143 /* It seems that we have exceeded capacity of the Wiener array
144 * Produce an error. */
145 err = error_raise(ERR_WIENER_ARRAY, __LINE__, EF_MCCC_WIENER);
146 }
147
148 if(!err) {
149 if(ip == -1){
150 /* There are no Wiener processes existing for tp > t. *
151 * The generated Wiener process then has a mean W(tm) and *
152 * variance t-tm. */
153
154 w->nextslot[eidx] = eidx;
155 w->time[eidx] = t;
156 for(int i=0; i<MCCC_NDIM; i++){
157 w->wiener[i + eidx*MCCC_NDIM] = w->wiener[i + im*MCCC_NDIM]
158 + sqrt(t-w->time[im])*rand5[i];
159 }
160 windex[0] = eidx;
161 w->nextslot[im] = eidx;
162 }
163 else{
164 /* A Wiener process for tp > t exist. Generate a new process
165 * using the rules set by the Brownian bridge. The rules are:
166 *
167 * mean = W(tm) + ( W(ip)-W(im) )*(t-tm)/(tp-tm)
168 * variance = (t-tm)*(tp-t)/(tp-tm) */
169 w->time[eidx] = t;
170 for(int i=0; i<MCCC_NDIM; i++){
171 w->wiener[i+eidx*MCCC_NDIM] =
172 w->wiener[i+im*MCCC_NDIM]
173 + ( w->wiener[i + ip*MCCC_NDIM]
174 - w->wiener[i + im*MCCC_NDIM] )
175 * ( t - w->time[im] ) / ( w->time[ip] - w->time[im] )
176 + sqrt( ( t - w->time[im] ) * ( w->time[ip] - t )
177 / ( w->time[ip] - w->time[im] ) ) * rand5[i];
178 }
179
180 /* Sort new wiener process to its correct place */
181 w->nextslot[eidx] = ip;
182 w->nextslot[im] = eidx;
183 windex[0] = eidx;
184 }
185 }
186 }
187
188 return err;
189}
190
204 a5err err = 0;
205 int idx, nextidx;
206
207 /* Remove processes W(t_i) until ti = t */
208 idx = 0;
209 real ti = w->time[idx];
210 while(ti < t){
211 nextidx = w->nextslot[idx];
212 if(idx == nextidx){
213 err = error_raise(ERR_WIENER_ARRAY, __LINE__, EF_MCCC_WIENER);
214 t = ti; // Breaks the loop
215 }
216 else {
217 w->nextslot[idx] = MCCC_EMPTY;
218 idx = nextidx;
219 ti = w->time[idx];
220 }
221 }
222
223 if(idx!=0 && !err){
224 /* Move W(t) process as the first one */
225 w->nextslot[0] = w->nextslot[idx];
226
227 w->time[0] = w->time[idx];
228 for(int i=0; i<MCCC_NDIM; i++){
229 w->wiener[i] = w->wiener[idx*MCCC_NDIM+i];
230 }
231
232 /* Check if the process is also the last one */
233 if( w->nextslot[idx] == idx ){
234 w->nextslot[0] = 0;
235 }
236 w->nextslot[idx] = MCCC_EMPTY;
237 }
238
239 return err;
240}
Main header file for ASCOT5.
double real
Definition ascot5.h:85
Header file containing physical and mathematical constants.
Error module for ASCOT5.
unsigned long int a5err
Simulation error flag.
Definition error.h:17
@ EF_MCCC_WIENER
Definition error.h:26
@ ERR_WIENER_ARRAY
Definition error.h:70
Header file for math.c.
const int MCCC_EMPTY
Definition mccc_wiener.c:27
a5err mccc_wiener_generate(mccc_wienarr *w, real t, int *windex, real *rand5)
Generates a new Wiener process at a given time instant.
Definition mccc_wiener.c:96
void mccc_wiener_onload(mccc_wienarr *w, int mrk_array_size)
Onload data from the GPU.
Definition mccc_wiener.c:73
a5err mccc_wiener_clean(mccc_wienarr *w, real t)
Removes Wiener processes from the array that are no longer required.
void mccc_wiener_offload(mccc_wienarr *w, int mrk_array_size)
Offload data to the accelerator.
Definition mccc_wiener.c:57
void mccc_wiener_initialize(mccc_wienarr *w, real initime)
Initializes a struct that stores generated Wiener processes.
Definition mccc_wiener.c:36
header file for mccc_wiener.c
#define MCCC_NSLOTS
Definition mccc_wiener.h:21
#define MCCC_NDIM
Definition mccc_wiener.h:15
Struct for storing Wiener processes.
Definition mccc_wiener.h:28
real time[MCCC_NSLOTS]
Definition mccc_wiener.h:33
int nextslot[MCCC_NSLOTS]
Definition mccc_wiener.h:29
real wiener[MCCC_NDIM *MCCC_NSLOTS]
Definition mccc_wiener.h:35