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
66a5err mccc_wiener_generate(mccc_wienarr* w, real t, int* windex, real* rand5){
67 a5err err = 0;
68 int eidx; /* Helper variables */
69 int im, ip; /* Indices of the Wiener processes for which tm < t < tp */
70
71 windex[0] = -1;
72 im = 0;
73 ip = -1; /* There isn't necessarily a Wiener process tp > t */
74
75 /* Find im and ip */
76 int idx = 0, breakloop = 0;
77 for(int i=0; i<MCCC_NSLOTS; i++){
78 if(!breakloop) {
79 if(w->nextslot[idx] == idx){
80 /* Reached last process. Break loop */
81 breakloop = 1;
82 }
83 if(w->time[idx] == t) {
84 /* Process already exists */
85 windex[0] = idx;
86 breakloop = 1;
87 }
88 else {
89 if(w->time[idx] < t ) {
90 /* Process i for which t_i < t */
91 im = idx;
92 }
93 if(w->time[w->nextslot[idx]] > t) {
94 /* Process i for which t_i > t */
95 ip = w->nextslot[idx];
96 breakloop = 1;
97 }
98 }
99 idx = w->nextslot[idx];
100 }
101 }
102
103 if(windex[0] == -1) {
104 /* Find an empty slot for the next process */
105 eidx = 0;
106 for(int i=0; i<MCCC_NSLOTS; i++){
107 if( w->nextslot[i] == MCCC_EMPTY){
108 eidx = i;
109 i = MCCC_NSLOTS;
110 }
111 }
112 if(eidx == 0){
113 /* It seems that we have exceeded capacity of the Wiener array
114 * Produce an error. */
116 }
117
118 if(!err) {
119 if(ip == -1){
120 /* There are no Wiener processes existing for tp > t. *
121 * The generated Wiener process then has a mean W(tm) and *
122 * variance t-tm. */
123
124 w->nextslot[eidx] = eidx;
125 w->time[eidx] = t;
126 for(int i=0; i<MCCC_NDIM; i++){
127 w->wiener[i + eidx*MCCC_NDIM] = w->wiener[i + im*MCCC_NDIM]
128 + sqrt(t-w->time[im])*rand5[i];
129 }
130 windex[0] = eidx;
131 w->nextslot[im] = eidx;
132 }
133 else{
134 /* A Wiener process for tp > t exist. Generate a new process
135 * using the rules set by the Brownian bridge. The rules are:
136 *
137 * mean = W(tm) + ( W(ip)-W(im) )*(t-tm)/(tp-tm)
138 * variance = (t-tm)*(tp-t)/(tp-tm) */
139 w->time[eidx] = t;
140 for(int i=0; i<MCCC_NDIM; i++){
141 w->wiener[i+eidx*MCCC_NDIM] =
142 w->wiener[i+im*MCCC_NDIM]
143 + ( w->wiener[i + ip*MCCC_NDIM]
144 - w->wiener[i + im*MCCC_NDIM] )
145 * ( t - w->time[im] ) / ( w->time[ip] - w->time[im] )
146 + sqrt( ( t - w->time[im] ) * ( w->time[ip] - t )
147 / ( w->time[ip] - w->time[im] ) ) * rand5[i];
148 }
149
150 /* Sort new wiener process to its correct place */
151 w->nextslot[eidx] = ip;
152 w->nextslot[im] = eidx;
153 windex[0] = eidx;
154 }
155 }
156 }
157
158 return err;
159}
160
174 a5err err = 0;
175 int idx, nextidx;
176
177 /* Remove processes W(t_i) until ti = t */
178 idx = 0;
179 real ti = w->time[idx];
180 while(ti < t){
181 nextidx = w->nextslot[idx];
182 if(idx == nextidx){
184 t = ti; // Breaks the loop
185 }
186 else {
187 w->nextslot[idx] = MCCC_EMPTY;
188 idx = nextidx;
189 ti = w->time[idx];
190 }
191 }
192
193 if(idx!=0 && !err){
194 /* Move W(t) process as the first one */
195 w->nextslot[0] = w->nextslot[idx];
196
197 w->time[0] = w->time[idx];
198 for(int i=0; i<MCCC_NDIM; i++){
199 w->wiener[i] = w->wiener[idx*MCCC_NDIM+i];
200 }
201
202 /* Check if the process is also the last one */
203 if( w->nextslot[idx] == idx ){
204 w->nextslot[0] = 0;
205 }
206 w->nextslot[idx] = MCCC_EMPTY;
207 }
208
209 return err;
210}
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:68
static DECLARE_TARGET_SIMD a5err error_raise(error_type type, int line, error_file file)
Raise a new error.
Definition error.h:86
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:66
a5err mccc_wiener_clean(mccc_wienarr *w, real t)
Removes Wiener processes from the array that are no longer required.
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