1 |
mbobra |
1.1 |
|
2 |
|
|
/*=========================================== |
3 |
|
|
|
4 |
|
|
The following 3 functions calculate the following spaceweather indices: |
5 |
|
|
|
6 |
|
|
USFLUX Total unsigned flux in Maxwells |
7 |
|
|
MEANGBZ Mean value of the vertical field gradient, in Gauss/Mm |
8 |
|
|
R_VALUE Karel Schrijver's R parameter |
9 |
|
|
|
10 |
mbobra |
1.2 |
The indices are calculated on the pixels in which the bitmap segment is greater than 36. |
11 |
mbobra |
1.1 |
|
12 |
mbobra |
1.2 |
The SMARP bitmap has 13 unique values because they describe three different characteristics: |
13 |
|
|
the location of the pixel (whether the pixel is off disk or a member of the patch), the |
14 |
|
|
character of the magnetic field (quiet or active), and the character of the continuum |
15 |
|
|
intensity data (quiet, part of faculae, part of a sunspot). |
16 |
|
|
|
17 |
|
|
Here are all the possible values: |
18 |
mbobra |
1.1 |
|
19 |
mbobra |
1.2 |
Value Keyword Definition |
20 |
|
|
0 OFFDISK The pixel is located somewhere off the solar disk. |
21 |
|
|
1 QUIET The pixel is associated with weak line-of-sight magnetic field. |
22 |
|
|
2 ACTIVE The pixel is associated with strong line-of-sight magnetic field. |
23 |
|
|
4 SPTQUIET The pixel is associated with no features in the continuum intensity data. |
24 |
|
|
8 SPTFACUL The pixel is associated with faculae in the continuum intensity data. |
25 |
|
|
16 SPTSPOT The pixel is associated with sunspots in the continuum intensity data. |
26 |
|
|
32 ON_PATCH The pixel is inside the patch. |
27 |
|
|
|
28 |
|
|
Here are all the possible permutations: |
29 |
|
|
|
30 |
|
|
Value Definition |
31 |
|
|
0 The pixel is located somewhere off the solar disk. |
32 |
|
|
5 The pixel is located outside the patch, associated with weak line-of-sight magnetic field, and no features in the continuum intensity data. |
33 |
|
|
9 The pixel is located outside the patch, associated with weak line-of-sight magnetic field, and faculae in the continuum intensity data. |
34 |
|
|
17 The pixel is located outside the patch, associated with weak line-of-sight magnetic field, and sunspots in the continuum intensity data. |
35 |
|
|
6 The pixel is located outside the patch, associated with strong line-of-sight magnetic field, and no features in the continuum intensity data. |
36 |
|
|
10 The pixel is located outside the patch, associated with strong line-of-sight magnetic field, and faculae in the continuum intensity data. |
37 |
|
|
18 The pixel is located outside the patch, associated with strong line-of-sight magnetic field, and sunspots in the continuum intensity data. |
38 |
|
|
37 The pixel is located inside the patch, associated with weak line-of-sight magnetic field, and no features in the continuum intensity data. |
39 |
|
|
41 The pixel is located inside the patch, associated with weak line-of-sight magnetic field, and faculae in the continuum intensity data. |
40 |
|
|
49 The pixel is located inside the patch, associated with weak line-of-sight magnetic field, and sunspots in the continuum intensity data. |
41 |
|
|
38 The pixel is located inside the patch, associated with strong line-of-sight magnetic field, and no features in the continuum intensity data. |
42 |
|
|
42 The pixel is located inside the patch, associated with strong line-of-sight magnetic field, and faculae in the continuum intensity data. |
43 |
|
|
50 The pixel is located inside the patch, associated with strong line-of-sight magnetic field, and sunspots in the continuum intensity data. |
44 |
|
|
|
45 |
|
|
Thus pixels with a value greater than 36 are located inside the patch. |
46 |
|
|
|
47 |
|
|
Written by Monica Bobra |
48 |
mbobra |
1.1 |
|
49 |
|
|
===========================================*/ |
50 |
|
|
#include <math.h> |
51 |
|
|
#include <mkl.h> |
52 |
|
|
|
53 |
|
|
#define PI (M_PI) |
54 |
|
|
#define MUNAUGHT (0.0000012566370614) /* magnetic constant */ |
55 |
|
|
|
56 |
|
|
/*===========================================*/ |
57 |
|
|
|
58 |
|
|
/* Example function 1: Compute total unsigned flux in units of G/cm^2 */ |
59 |
|
|
|
60 |
|
|
// To compute the unsigned flux, we simply calculate |
61 |
|
|
// flux = surface integral [(vector Bz) dot (normal vector)], |
62 |
|
|
// = surface integral [(magnitude Bz)*(magnitude normal)*(cos theta)]. |
63 |
|
|
// However, since the field is radial, we will assume cos theta = 1. |
64 |
|
|
// Therefore the pixels only need to be corrected for the projection. |
65 |
|
|
|
66 |
|
|
// To convert G to G*cm^2, simply multiply by the number of square centimeters per pixel. |
67 |
|
|
// As an order of magnitude estimate, we can assign 0.5 to CDELT1 and 722500m/arcsec to (RSUN_REF/RSUN_OBS). |
68 |
|
|
// (Gauss/pix^2)(CDELT1)^2(RSUN_REF/RSUN_OBS)^2(100.cm/m)^2 |
69 |
|
|
// =Gauss*cm^2 |
70 |
|
|
|
71 |
|
|
int computeAbsFlux(float *bz, int *dims, float *absFlux, |
72 |
|
|
float *mean_vf_ptr, float *count_mask_ptr, |
73 |
|
|
int *bitmask, float cdelt1, double rsun_ref, double rsun_obs) |
74 |
|
|
|
75 |
|
|
{ |
76 |
|
|
|
77 |
|
|
int nx = dims[0]; |
78 |
|
|
int ny = dims[1]; |
79 |
|
|
int i = 0; |
80 |
|
|
int j = 0; |
81 |
|
|
int count_mask = 0; |
82 |
|
|
double sum = 0.0; |
83 |
|
|
*absFlux = 0.0; |
84 |
|
|
*mean_vf_ptr = 0.0; |
85 |
|
|
|
86 |
|
|
|
87 |
|
|
if (nx <= 0 || ny <= 0) return 1; |
88 |
|
|
|
89 |
|
|
for (i = 0; i < nx; i++) |
90 |
|
|
{ |
91 |
|
|
for (j = 0; j < ny; j++) |
92 |
|
|
{ |
93 |
mbobra |
1.2 |
if ( bitmask[j * nx + i] < 36 ) continue; |
94 |
mbobra |
1.1 |
if isnan(bz[j * nx + i]) continue; |
95 |
|
|
sum += (fabs(bz[j * nx + i])); |
96 |
|
|
count_mask++; |
97 |
|
|
} |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
*mean_vf_ptr = sum*cdelt1*cdelt1*(rsun_ref/rsun_obs)*(rsun_ref/rsun_obs)*100.0*100.0; |
101 |
|
|
*count_mask_ptr = count_mask; |
102 |
|
|
//printf("mean_vf_ptr=%f\n",*mean_vf_ptr); |
103 |
|
|
//printf("count_mask_ptr=%f\n",*count_mask_ptr); |
104 |
|
|
//printf("cdelt1=%f\n",cdelt1); |
105 |
|
|
//printf("rsun_ref=%f\n",rsun_ref); |
106 |
|
|
//printf("rsun_obs=%f\n",rsun_obs); |
107 |
|
|
|
108 |
|
|
return 0; |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
/*===========================================*/ |
112 |
|
|
/* Example function 2: Derivative of B_vertical SQRT( (dBz/dx)^2 + (dBz/dy)^2 ) */ |
113 |
|
|
|
114 |
|
|
int computeBzderivative(float *bz, int *dims, float *mean_derivative_bz_ptr, int *bitmask, float *derx_bz, float *dery_bz) |
115 |
|
|
{ |
116 |
|
|
|
117 |
|
|
int nx = dims[0]; |
118 |
|
|
int ny = dims[1]; |
119 |
|
|
int i = 0; |
120 |
|
|
int j = 0; |
121 |
|
|
int count_mask = 0; |
122 |
|
|
double sum = 0.0; |
123 |
|
|
*mean_derivative_bz_ptr = 0.0; |
124 |
|
|
|
125 |
|
|
if (nx <= 0 || ny <= 0) return 1; |
126 |
|
|
|
127 |
|
|
/* brute force method of calculating the derivative (no consideration for edges) */ |
128 |
|
|
for (i = 1; i <= nx-2; i++) |
129 |
|
|
{ |
130 |
|
|
for (j = 0; j <= ny-1; j++) |
131 |
|
|
{ |
132 |
|
|
derx_bz[j * nx + i] = (bz[j * nx + i+1] - bz[j * nx + i-1])*0.5; |
133 |
|
|
} |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
/* brute force method of calculating the derivative (no consideration for edges) */ |
137 |
|
|
for (i = 0; i <= nx-1; i++) |
138 |
|
|
{ |
139 |
|
|
for (j = 1; j <= ny-2; j++) |
140 |
|
|
{ |
141 |
|
|
dery_bz[j * nx + i] = (bz[(j+1) * nx + i] - bz[(j-1) * nx + i])*0.5; |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
/* consider the edges for the arrays that contribute to the variable "sum" in the computation below. |
146 |
|
|
ignore the edges for the error terms as those arrays have been initialized to zero. |
147 |
|
|
this is okay because the error term will ultimately not include the edge pixels as they are selected out by the mask and bitmask arrays.*/ |
148 |
|
|
i=0; |
149 |
|
|
for (j = 0; j <= ny-1; j++) |
150 |
|
|
{ |
151 |
|
|
derx_bz[j * nx + i] = ( (-3*bz[j * nx + i]) + (4*bz[j * nx + (i+1)]) - (bz[j * nx + (i+2)]) )*0.5; |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
i=nx-1; |
155 |
|
|
for (j = 0; j <= ny-1; j++) |
156 |
|
|
{ |
157 |
|
|
derx_bz[j * nx + i] = ( (3*bz[j * nx + i]) + (-4*bz[j * nx + (i-1)]) - (-bz[j * nx + (i-2)]) )*0.5; |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
j=0; |
161 |
|
|
for (i = 0; i <= nx-1; i++) |
162 |
|
|
{ |
163 |
|
|
dery_bz[j * nx + i] = ( (-3*bz[j*nx + i]) + (4*bz[(j+1) * nx + i]) - (bz[(j+2) * nx + i]) )*0.5; |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
j=ny-1; |
167 |
|
|
for (i = 0; i <= nx-1; i++) |
168 |
|
|
{ |
169 |
|
|
dery_bz[j * nx + i] = ( (3*bz[j * nx + i]) + (-4*bz[(j-1) * nx + i]) - (-bz[(j-2) * nx + i]) )*0.5; |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
|
173 |
|
|
for (i = 0; i <= nx-1; i++) |
174 |
|
|
{ |
175 |
|
|
for (j = 0; j <= ny-1; j++) |
176 |
|
|
{ |
177 |
mbobra |
1.2 |
if ( bitmask[j * nx + i] < 36 ) continue; |
178 |
mbobra |
1.1 |
if ( (derx_bz[j * nx + i] + dery_bz[j * nx + i]) == 0) continue; |
179 |
|
|
if isnan(bz[j * nx + i]) continue; |
180 |
|
|
if isnan(bz[(j+1) * nx + i]) continue; |
181 |
|
|
if isnan(bz[(j-1) * nx + i]) continue; |
182 |
|
|
if isnan(bz[j * nx + i-1]) continue; |
183 |
|
|
if isnan(bz[j * nx + i+1]) continue; |
184 |
|
|
if isnan(derx_bz[j * nx + i]) continue; |
185 |
|
|
if isnan(dery_bz[j * nx + i]) continue; |
186 |
|
|
sum += sqrt( derx_bz[j * nx + i]*derx_bz[j * nx + i] + dery_bz[j * nx + i]*dery_bz[j * nx + i] ); /* Units of Gauss */ |
187 |
|
|
count_mask++; |
188 |
|
|
} |
189 |
|
|
} |
190 |
|
|
|
191 |
|
|
*mean_derivative_bz_ptr = (sum)/(count_mask); // would be divided by ((nx-2)*(ny-2)) if shape of count_mask = shape of magnetogram |
192 |
|
|
//printf("mean_derivative_bz_ptr=%f\n",*mean_derivative_bz_ptr); |
193 |
|
|
|
194 |
|
|
return 0; |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
/*===========================================*/ |
198 |
|
|
/* Example function 3: R parameter as defined in Schrijver, 2007 */ |
199 |
|
|
// |
200 |
|
|
// Note that there is a restriction on the function fsample() |
201 |
|
|
// If the following occurs: |
202 |
|
|
// nx_out > floor((ny_in-1)/scale + 1) |
203 |
|
|
// ny_out > floor((ny_in-1)/scale + 1), |
204 |
|
|
// where n*_out are the dimensions of the output array and n*_in |
205 |
|
|
// are the dimensions of the input array, fsample() will usually result |
206 |
|
|
// in a segfault (though not always, depending on how the segfault was accessed.) |
207 |
|
|
|
208 |
|
|
int computeR(float *los, int *dims, float *Rparam, float cdelt1, |
209 |
|
|
float *rim, float *p1p0, float *p1n0, float *p1p, float *p1n, float *p1, |
210 |
|
|
float *pmap, int nx1, int ny1, |
211 |
|
|
int scale, float *p1pad, int nxp, int nyp, float *pmapn) |
212 |
|
|
|
213 |
|
|
{ |
214 |
|
|
int nx = dims[0]; |
215 |
|
|
int ny = dims[1]; |
216 |
|
|
int i = 0; |
217 |
|
|
int j = 0; |
218 |
|
|
int index, index1; |
219 |
|
|
double sum = 0.0; |
220 |
|
|
*Rparam = 0.0; |
221 |
|
|
struct fresize_struct fresboxcar, fresgauss; |
222 |
|
|
struct fint_struct fints; |
223 |
|
|
float sigma = 10.0/2.3548; |
224 |
|
|
|
225 |
|
|
// set up convolution kernels |
226 |
|
|
init_fresize_boxcar(&fresboxcar,1,1); |
227 |
|
|
init_fresize_gaussian(&fresgauss,sigma,20,1); |
228 |
|
|
|
229 |
|
|
// =============== [STEP 1] =============== |
230 |
|
|
// bin the line-of-sight magnetogram down by a factor of scale |
231 |
|
|
fsample(los, rim, nx, ny, nx, nx1, ny1, nx1, scale, 0, 0, 0.0); |
232 |
|
|
|
233 |
|
|
// =============== [STEP 2] =============== |
234 |
|
|
// identify positive and negative pixels greater than +/- 150 gauss |
235 |
|
|
// and label those pixels with a 1.0 in arrays p1p0 and p1n0 |
236 |
|
|
for (i = 0; i < nx1; i++) |
237 |
|
|
{ |
238 |
|
|
for (j = 0; j < ny1; j++) |
239 |
|
|
{ |
240 |
|
|
index = j * nx1 + i; |
241 |
|
|
if (rim[index] > 150) |
242 |
|
|
p1p0[index]=1.0; |
243 |
|
|
else |
244 |
|
|
p1p0[index]=0.0; |
245 |
|
|
if (rim[index] < -150) |
246 |
|
|
p1n0[index]=1.0; |
247 |
|
|
else |
248 |
|
|
p1n0[index]=0.0; |
249 |
|
|
} |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
// =============== [STEP 3] =============== |
253 |
|
|
// smooth each of the negative and positive pixel bitmaps |
254 |
|
|
fresize(&fresboxcar, p1p0, p1p, nx1, ny1, nx1, nx1, ny1, nx1, 0, 0, 0.0); |
255 |
|
|
fresize(&fresboxcar, p1n0, p1n, nx1, ny1, nx1, nx1, ny1, nx1, 0, 0, 0.0); |
256 |
|
|
|
257 |
|
|
// =============== [STEP 4] =============== |
258 |
|
|
// find the pixels for which p1p and p1n are both equal to 1. |
259 |
|
|
// this defines the polarity inversion line |
260 |
|
|
for (i = 0; i < nx1; i++) |
261 |
|
|
{ |
262 |
|
|
for (j = 0; j < ny1; j++) |
263 |
|
|
{ |
264 |
|
|
index = j * nx1 + i; |
265 |
|
|
if ((p1p[index] > 0.0) && (p1n[index] > 0.0)) |
266 |
|
|
p1[index]=1.0; |
267 |
|
|
else |
268 |
|
|
p1[index]=0.0; |
269 |
|
|
} |
270 |
|
|
} |
271 |
|
|
|
272 |
|
|
// pad p1 with zeroes so that the gaussian colvolution in step 5 |
273 |
|
|
// does not cut off data within hwidth of the edge |
274 |
|
|
|
275 |
|
|
// step i: zero p1pad |
276 |
|
|
for (i = 0; i < nxp; i++) |
277 |
|
|
{ |
278 |
|
|
for (j = 0; j < nyp; j++) |
279 |
|
|
{ |
280 |
|
|
index = j * nxp + i; |
281 |
|
|
p1pad[index]=0.0; |
282 |
|
|
} |
283 |
|
|
} |
284 |
|
|
|
285 |
|
|
// step ii: place p1 at the center of p1pad |
286 |
|
|
for (i = 0; i < nx1; i++) |
287 |
|
|
{ |
288 |
|
|
for (j = 0; j < ny1; j++) |
289 |
|
|
{ |
290 |
|
|
index = j * nx1 + i; |
291 |
|
|
index1 = (j+20) * nxp + (i+20); |
292 |
|
|
p1pad[index1]=p1[index]; |
293 |
|
|
} |
294 |
|
|
} |
295 |
|
|
|
296 |
|
|
// =============== [STEP 5] =============== |
297 |
|
|
// convolve the polarity inversion line map with a gaussian |
298 |
|
|
// to identify the region near the plarity inversion line |
299 |
|
|
// the resultant array is called pmap |
300 |
|
|
fresize(&fresgauss, p1pad, pmap, nxp, nyp, nxp, nxp, nyp, nxp, 0, 0, 0.0); |
301 |
|
|
|
302 |
|
|
|
303 |
|
|
// select out the nx1 x ny1 non-padded array within pmap |
304 |
|
|
for (i = 0; i < nx1; i++) |
305 |
|
|
{ |
306 |
|
|
for (j = 0; j < ny1; j++) |
307 |
|
|
{ |
308 |
|
|
index = j * nx1 + i; |
309 |
|
|
index1 = (j+20) * nxp + (i+20); |
310 |
|
|
pmapn[index]=pmap[index1]; |
311 |
|
|
} |
312 |
|
|
} |
313 |
|
|
|
314 |
|
|
// =============== [STEP 6] =============== |
315 |
|
|
// the R parameter is calculated |
316 |
|
|
for (i = 0; i < nx1; i++) |
317 |
|
|
{ |
318 |
|
|
for (j = 0; j < ny1; j++) |
319 |
|
|
{ |
320 |
|
|
index = j * nx1 + i; |
321 |
|
|
if isnan(pmapn[index]) continue; |
322 |
|
|
if isnan(rim[index]) continue; |
323 |
|
|
sum += pmapn[index]*abs(rim[index]); |
324 |
|
|
} |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
if (sum < 1.0) |
328 |
|
|
*Rparam = 0.0; |
329 |
|
|
else |
330 |
|
|
*Rparam = log10(sum); |
331 |
|
|
|
332 |
|
|
//printf("R_VALUE=%f\n",*Rparam); |
333 |
|
|
|
334 |
|
|
free_fresize(&fresboxcar); |
335 |
|
|
free_fresize(&fresgauss); |
336 |
|
|
|
337 |
|
|
return 0; |
338 |
|
|
|
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
/*===========================================*/ |
342 |
|
|
|
343 |
|
|
char *smarp_functions_version() // Returns CVS version of smarp_functions.c |
344 |
|
|
{ |
345 |
|
|
return strdup("$Id"); |
346 |
|
|
} |