ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/sharp/apps/sw_functions.c
Revision: 1.37
Committed: Fri Oct 30 20:21:28 2015 UTC (7 years, 10 months ago) by mbobra
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_9-1, Ver_9-3, Ver_9-2, Ver_9-4, Ver_8-11, Ver_8-12, Ver_9-0
Changes since 1.36: +28 -39 lines
Log Message:
reverted to 1.35 and added comment to SAVNCPP header

File Contents

# Content
1
2 /*===========================================
3
4 The following 14 functions calculate the following spaceweather indices:
5
6 USFLUX Total unsigned flux in Maxwells
7 MEANGAM Mean inclination angle, gamma, in degrees
8 MEANGBT Mean value of the total field gradient, in Gauss/Mm
9 MEANGBZ Mean value of the vertical field gradient, in Gauss/Mm
10 MEANGBH Mean value of the horizontal field gradient, in Gauss/Mm
11 MEANJZD Mean vertical current density, in mA/m2
12 TOTUSJZ Total unsigned vertical current, in Amperes
13 MEANALP Mean twist parameter, alpha, in 1/Mm
14 MEANJZH Mean current helicity in G2/m
15 TOTUSJH Total unsigned current helicity in G2/m
16 ABSNJZH Absolute value of the net current helicity in G2/m
17 SAVNCPP Sum of the Absolute Value of the Net Currents Per Polarity in Amperes
18 MEANPOT Mean photospheric excess magnetic energy density in ergs per cubic centimeter
19 TOTPOT Total photospheric magnetic energy density in ergs per cubic centimeter
20 MEANSHR Mean shear angle (measured using Btotal) in degrees
21 R_VALUE Karel Schrijver's R parameter
22
23 The indices are calculated on the pixels in which the conf_disambig segment is greater than 70 and
24 pixels in which the bitmap segment is greater than 30. These ranges are selected because the CCD
25 coordinate bitmaps are interpolated for certain data (at the time of this CVS submit, all data
26 prior to 2013.08.21_17:24:00_TAI contain interpolated bitmaps; data post-2013.08.21_17:24:00_TAI
27 contain nearest-neighbor bitmaps).
28
29 In the CCD coordinates, this means that we are selecting the pixels that equal 90 in conf_disambig
30 and the pixels that equal 33 or 34 in bitmap. Here are the definitions of the pixel values:
31
32 For conf_disambig:
33 50 : not all solutions agree (weak field method applied)
34 60 : not all solutions agree (weak field + annealed)
35 90 : all solutions agree (strong field + annealed)
36 0 : not disambiguated
37
38 For bitmap:
39 1 : weak field outside smooth bounding curve
40 2 : strong field outside smooth bounding curve
41 33 : weak field inside smooth bounding curve
42 34 : strong field inside smooth bounding curve
43
44 Written by Monica Bobra 15 August 2012
45 Potential Field code (appended) written by Keiji Hayashi
46 Error analysis modification 21 October 2013
47
48 ===========================================*/
49 #include <math.h>
50 #include <mkl.h>
51
52 #define PI (M_PI)
53 #define MUNAUGHT (0.0000012566370614) /* magnetic constant */
54
55 /*===========================================*/
56
57 /* Example function 1: Compute total unsigned flux in units of G/cm^2 */
58
59 // To compute the unsigned flux, we simply calculate
60 // flux = surface integral [(vector Bz) dot (normal vector)],
61 // = surface integral [(magnitude Bz)*(magnitude normal)*(cos theta)].
62 // However, since the field is radial, we will assume cos theta = 1.
63 // Therefore the pixels only need to be corrected for the projection.
64
65 // To convert G to G*cm^2, simply multiply by the number of square centimeters per pixel.
66 // As an order of magnitude estimate, we can assign 0.5 to CDELT1 and 722500m/arcsec to (RSUN_REF/RSUN_OBS).
67 // (Gauss/pix^2)(CDELT1)^2(RSUN_REF/RSUN_OBS)^2(100.cm/m)^2
68 // =Gauss*cm^2
69
70 int computeAbsFlux(float *bz_err, float *bz, int *dims, float *absFlux,
71 float *mean_vf_ptr, float *mean_vf_err_ptr, float *count_mask_ptr, int *mask,
72 int *bitmask, float cdelt1, double rsun_ref, double rsun_obs)
73
74 {
75
76 int nx = dims[0];
77 int ny = dims[1];
78 int i = 0;
79 int j = 0;
80 int count_mask = 0;
81 double sum = 0.0;
82 double err = 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 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
94 if isnan(bz[j * nx + i]) continue;
95 sum += (fabs(bz[j * nx + i]));
96 err += bz_err[j * nx + i]*bz_err[j * nx + i];
97 count_mask++;
98 }
99 }
100
101 *mean_vf_ptr = sum*cdelt1*cdelt1*(rsun_ref/rsun_obs)*(rsun_ref/rsun_obs)*100.0*100.0;
102 *mean_vf_err_ptr = (sqrt(err))*fabs(cdelt1*cdelt1*(rsun_ref/rsun_obs)*(rsun_ref/rsun_obs)*100.0*100.0); // error in the unsigned flux
103 *count_mask_ptr = count_mask;
104 return 0;
105 }
106
107 /*===========================================*/
108 /* Example function 2: Calculate Bh, the horizontal field, in units of Gauss */
109 // Native units of Bh are Gauss
110
111 int computeBh(float *bx_err, float *by_err, float *bh_err, float *bx, float *by, float *bz, float *bh, int *dims,
112 float *mean_hf_ptr, int *mask, int *bitmask)
113
114 {
115
116 int nx = dims[0];
117 int ny = dims[1];
118 int i = 0;
119 int j = 0;
120 int count_mask = 0;
121 double sum = 0.0;
122 *mean_hf_ptr = 0.0;
123
124 if (nx <= 0 || ny <= 0) return 1;
125
126 for (i = 0; i < nx; i++)
127 {
128 for (j = 0; j < ny; j++)
129 {
130 if isnan(bx[j * nx + i])
131 {
132 bh[j * nx + i] = NAN;
133 bh_err[j * nx + i] = NAN;
134 continue;
135 }
136 if isnan(by[j * nx + i])
137 {
138 bh[j * nx + i] = NAN;
139 bh_err[j * nx + i] = NAN;
140 continue;
141 }
142 bh[j * nx + i] = sqrt( bx[j * nx + i]*bx[j * nx + i] + by[j * nx + i]*by[j * nx + i] );
143 sum += bh[j * nx + i];
144 bh_err[j * nx + i]=sqrt( bx[j * nx + i]*bx[j * nx + i]*bx_err[j * nx + i]*bx_err[j * nx + i] + by[j * nx + i]*by[j * nx + i]*by_err[j * nx + i]*by_err[j * nx + i])/ bh[j * nx + i];
145 count_mask++;
146 }
147 }
148
149 *mean_hf_ptr = sum/(count_mask); // would be divided by nx*ny if shape of count_mask = shape of magnetogram
150
151 return 0;
152 }
153
154 /*===========================================*/
155 /* Example function 3: Calculate Gamma in units of degrees */
156 // Native units of atan(x) are in radians; to convert from radians to degrees, multiply by (180./PI)
157 //
158 // Error analysis calculations are done in radians (since derivatives are only true in units of radians),
159 // and multiplied by (180./PI) at the end for consistency in units.
160
161 int computeGamma(float *bz_err, float *bh_err, float *bx, float *by, float *bz, float *bh, int *dims,
162 float *mean_gamma_ptr, float *mean_gamma_err_ptr, int *mask, int *bitmask)
163 {
164 int nx = dims[0];
165 int ny = dims[1];
166 int i = 0;
167 int j = 0;
168 int count_mask = 0;
169 double sum = 0.0;
170 double err = 0.0;
171 *mean_gamma_ptr = 0.0;
172
173 if (nx <= 0 || ny <= 0) return 1;
174
175 for (i = 0; i < nx; i++)
176 {
177 for (j = 0; j < ny; j++)
178 {
179 if (bh[j * nx + i] > 100)
180 {
181 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
182 if isnan(bz[j * nx + i]) continue;
183 if isnan(bz_err[j * nx + i]) continue;
184 if isnan(bh_err[j * nx + i]) continue;
185 if isnan(bh[j * nx + i]) continue;
186 if (bz[j * nx + i] == 0) continue;
187 sum += fabs(atan(bh[j * nx + i]/fabs(bz[j * nx + i])))*(180./PI);
188 err += (1/(1+((bh[j * nx + i]*bh[j * nx + i])/(bz[j * nx + i]*bz[j * nx + i]))))*(1/(1+((bh[j * nx + i]*bh[j * nx + i])/(bz[j * nx + i]*bz[j * nx + i])))) *
189 ( ((bh_err[j * nx + i]*bh_err[j * nx + i])/(bz[j * nx + i]*bz[j * nx + i])) +
190 ((bh[j * nx + i]*bh[j * nx + i]*bz_err[j * nx + i]*bz_err[j * nx + i])/(bz[j * nx + i]*bz[j * nx + i]*bz[j * nx + i]*bz[j * nx + i])) );
191 count_mask++;
192 }
193 }
194 }
195
196 *mean_gamma_ptr = sum/count_mask;
197 *mean_gamma_err_ptr = (sqrt(err)/(count_mask))*(180./PI);
198 //printf("MEANGAM=%f\n",*mean_gamma_ptr);
199 //printf("MEANGAM_err=%f\n",*mean_gamma_err_ptr);
200 return 0;
201 }
202
203 /*===========================================*/
204 /* Example function 4: Calculate B_Total*/
205 // Native units of B_Total are in gauss
206
207 int computeB_total(float *bx_err, float *by_err, float *bz_err, float *bt_err, float *bx, float *by, float *bz, float *bt, int *dims, int *mask, int *bitmask)
208 {
209
210 int nx = dims[0];
211 int ny = dims[1];
212 int i = 0;
213 int j = 0;
214 int count_mask = 0;
215
216 if (nx <= 0 || ny <= 0) return 1;
217
218 for (i = 0; i < nx; i++)
219 {
220 for (j = 0; j < ny; j++)
221 {
222 if isnan(bx[j * nx + i])
223 {
224 bt[j * nx + i] = NAN;
225 bt_err[j * nx + i] = NAN;
226 continue;
227 }
228 if isnan(by[j * nx + i])
229 {
230 bt[j * nx + i] = NAN;
231 bt_err[j * nx + i] = NAN;
232 continue;
233 }
234 if isnan(bz[j * nx + i])
235 {
236 bt[j * nx + i] = NAN;
237 bt_err[j * nx + i] = NAN;
238 continue;
239 }
240 bt[j * nx + i] = sqrt( bx[j * nx + i]*bx[j * nx + i] + by[j * nx + i]*by[j * nx + i] + bz[j * nx + i]*bz[j * nx + i]);
241 bt_err[j * nx + i]=sqrt(bx[j * nx + i]*bx[j * nx + i]*bx_err[j * nx + i]*bx_err[j * nx + i] + by[j * nx + i]*by[j * nx + i]*by_err[j * nx + i]*by_err[j * nx + i] + bz[j * nx + i]*bz[j * nx + i]*bz_err[j * nx + i]*bz_err[j * nx + i] ) / bt[j * nx + i];
242 }
243 }
244 return 0;
245 }
246
247 /*===========================================*/
248 /* Example function 5: Derivative of B_Total SQRT( (dBt/dx)^2 + (dBt/dy)^2 ) */
249
250 int computeBtotalderivative(float *bt, int *dims, float *mean_derivative_btotal_ptr, int *mask, int *bitmask, float *derx_bt, float *dery_bt, float *bt_err, float *mean_derivative_btotal_err_ptr, float *err_termAt, float *err_termBt)
251 {
252
253 int nx = dims[0];
254 int ny = dims[1];
255 int i = 0;
256 int j = 0;
257 int count_mask = 0;
258 double sum = 0.0;
259 double err = 0.0;
260 *mean_derivative_btotal_ptr = 0.0;
261
262 if (nx <= 0 || ny <= 0) return 1;
263
264 /* brute force method of calculating the derivative (no consideration for edges) */
265 for (i = 1; i <= nx-2; i++)
266 {
267 for (j = 0; j <= ny-1; j++)
268 {
269 derx_bt[j * nx + i] = (bt[j * nx + i+1] - bt[j * nx + i-1])*0.5;
270 err_termAt[j * nx + i] = (((bt[j * nx + (i+1)]-bt[j * nx + (i-1)])*(bt[j * nx + (i+1)]-bt[j * nx + (i-1)])) * (bt_err[j * nx + (i+1)]*bt_err[j * nx + (i+1)] + bt_err[j * nx + (i-1)]*bt_err[j * nx + (i-1)])) ;
271 }
272 }
273
274 /* brute force method of calculating the derivative (no consideration for edges) */
275 for (i = 0; i <= nx-1; i++)
276 {
277 for (j = 1; j <= ny-2; j++)
278 {
279 dery_bt[j * nx + i] = (bt[(j+1) * nx + i] - bt[(j-1) * nx + i])*0.5;
280 err_termBt[j * nx + i] = (((bt[(j+1) * nx + i]-bt[(j-1) * nx + i])*(bt[(j+1) * nx + i]-bt[(j-1) * nx + i])) * (bt_err[(j+1) * nx + i]*bt_err[(j+1) * nx + i] + bt_err[(j-1) * nx + i]*bt_err[(j-1) * nx + i])) ;
281 }
282 }
283
284 /* consider the edges for the arrays that contribute to the variable "sum" in the computation below.
285 ignore the edges for the error terms as those arrays have been initialized to zero.
286 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.*/
287 i=0;
288 for (j = 0; j <= ny-1; j++)
289 {
290 derx_bt[j * nx + i] = ( (-3*bt[j * nx + i]) + (4*bt[j * nx + (i+1)]) - (bt[j * nx + (i+2)]) )*0.5;
291 }
292
293 i=nx-1;
294 for (j = 0; j <= ny-1; j++)
295 {
296 derx_bt[j * nx + i] = ( (3*bt[j * nx + i]) + (-4*bt[j * nx + (i-1)]) - (-bt[j * nx + (i-2)]) )*0.5;
297 }
298
299 j=0;
300 for (i = 0; i <= nx-1; i++)
301 {
302 dery_bt[j * nx + i] = ( (-3*bt[j*nx + i]) + (4*bt[(j+1) * nx + i]) - (bt[(j+2) * nx + i]) )*0.5;
303 }
304
305 j=ny-1;
306 for (i = 0; i <= nx-1; i++)
307 {
308 dery_bt[j * nx + i] = ( (3*bt[j * nx + i]) + (-4*bt[(j-1) * nx + i]) - (-bt[(j-2) * nx + i]) )*0.5;
309 }
310
311 // Calculate the sum only
312 for (i = 1; i <= nx-2; i++)
313 {
314 for (j = 1; j <= ny-2; j++)
315 {
316 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
317 if ( (derx_bt[j * nx + i] + dery_bt[j * nx + i]) == 0) continue;
318 if isnan(bt[j * nx + i]) continue;
319 if isnan(bt[(j+1) * nx + i]) continue;
320 if isnan(bt[(j-1) * nx + i]) continue;
321 if isnan(bt[j * nx + i-1]) continue;
322 if isnan(bt[j * nx + i+1]) continue;
323 if isnan(bt_err[j * nx + i]) continue;
324 if isnan(derx_bt[j * nx + i]) continue;
325 if isnan(dery_bt[j * nx + i]) continue;
326 sum += sqrt( derx_bt[j * nx + i]*derx_bt[j * nx + i] + dery_bt[j * nx + i]*dery_bt[j * nx + i] ); /* Units of Gauss */
327 err += err_termBt[j * nx + i] / (16.0*( derx_bt[j * nx + i]*derx_bt[j * nx + i] + dery_bt[j * nx + i]*dery_bt[j * nx + i] ))+
328 err_termAt[j * nx + i] / (16.0*( derx_bt[j * nx + i]*derx_bt[j * nx + i] + dery_bt[j * nx + i]*dery_bt[j * nx + i] )) ;
329 count_mask++;
330 }
331 }
332
333 *mean_derivative_btotal_ptr = (sum)/(count_mask);
334 *mean_derivative_btotal_err_ptr = (sqrt(err))/(count_mask);
335 //printf("MEANGBT=%f\n",*mean_derivative_btotal_ptr);
336 //printf("MEANGBT_err=%f\n",*mean_derivative_btotal_err_ptr);
337
338 return 0;
339 }
340
341
342 /*===========================================*/
343 /* Example function 6: Derivative of Bh SQRT( (dBh/dx)^2 + (dBh/dy)^2 ) */
344
345 int computeBhderivative(float *bh, float *bh_err, int *dims, float *mean_derivative_bh_ptr, float *mean_derivative_bh_err_ptr, int *mask, int *bitmask, float *derx_bh, float *dery_bh, float *err_termAh, float *err_termBh)
346 {
347
348 int nx = dims[0];
349 int ny = dims[1];
350 int i = 0;
351 int j = 0;
352 int count_mask = 0;
353 double sum= 0.0;
354 double err =0.0;
355 *mean_derivative_bh_ptr = 0.0;
356
357 if (nx <= 0 || ny <= 0) return 1;
358
359 /* brute force method of calculating the derivative (no consideration for edges) */
360 for (i = 1; i <= nx-2; i++)
361 {
362 for (j = 0; j <= ny-1; j++)
363 {
364 derx_bh[j * nx + i] = (bh[j * nx + i+1] - bh[j * nx + i-1])*0.5;
365 err_termAh[j * nx + i] = (((bh[j * nx + (i+1)]-bh[j * nx + (i-1)])*(bh[j * nx + (i+1)]-bh[j * nx + (i-1)])) * (bh_err[j * nx + (i+1)]*bh_err[j * nx + (i+1)] + bh_err[j * nx + (i-1)]*bh_err[j * nx + (i-1)]));
366 }
367 }
368
369 /* brute force method of calculating the derivative (no consideration for edges) */
370 for (i = 0; i <= nx-1; i++)
371 {
372 for (j = 1; j <= ny-2; j++)
373 {
374 dery_bh[j * nx + i] = (bh[(j+1) * nx + i] - bh[(j-1) * nx + i])*0.5;
375 err_termBh[j * nx + i] = (((bh[ (j+1) * nx + i]-bh[(j-1) * nx + i])*(bh[(j+1) * nx + i]-bh[(j-1) * nx + i])) * (bh_err[(j+1) * nx + i]*bh_err[(j+1) * nx + i] + bh_err[(j-1) * nx + i]*bh_err[(j-1) * nx + i]));
376 }
377 }
378
379 /* consider the edges for the arrays that contribute to the variable "sum" in the computation below.
380 ignore the edges for the error terms as those arrays have been initialized to zero.
381 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.*/
382 i=0;
383 for (j = 0; j <= ny-1; j++)
384 {
385 derx_bh[j * nx + i] = ( (-3*bh[j * nx + i]) + (4*bh[j * nx + (i+1)]) - (bh[j * nx + (i+2)]) )*0.5;
386 }
387
388 i=nx-1;
389 for (j = 0; j <= ny-1; j++)
390 {
391 derx_bh[j * nx + i] = ( (3*bh[j * nx + i]) + (-4*bh[j * nx + (i-1)]) - (-bh[j * nx + (i-2)]) )*0.5;
392 }
393
394 j=0;
395 for (i = 0; i <= nx-1; i++)
396 {
397 dery_bh[j * nx + i] = ( (-3*bh[j*nx + i]) + (4*bh[(j+1) * nx + i]) - (bh[(j+2) * nx + i]) )*0.5;
398 }
399
400 j=ny-1;
401 for (i = 0; i <= nx-1; i++)
402 {
403 dery_bh[j * nx + i] = ( (3*bh[j * nx + i]) + (-4*bh[(j-1) * nx + i]) - (-bh[(j-2) * nx + i]) )*0.5;
404 }
405
406
407 for (i = 0; i <= nx-1; i++)
408 {
409 for (j = 0; j <= ny-1; j++)
410 {
411 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
412 if ( (derx_bh[j * nx + i] + dery_bh[j * nx + i]) == 0) continue;
413 if isnan(bh[j * nx + i]) continue;
414 if isnan(bh[(j+1) * nx + i]) continue;
415 if isnan(bh[(j-1) * nx + i]) continue;
416 if isnan(bh[j * nx + i-1]) continue;
417 if isnan(bh[j * nx + i+1]) continue;
418 if isnan(bh_err[j * nx + i]) continue;
419 if isnan(derx_bh[j * nx + i]) continue;
420 if isnan(dery_bh[j * nx + i]) continue;
421 sum += sqrt( derx_bh[j * nx + i]*derx_bh[j * nx + i] + dery_bh[j * nx + i]*dery_bh[j * nx + i] ); /* Units of Gauss */
422 err += err_termBh[j * nx + i] / (16.0*( derx_bh[j * nx + i]*derx_bh[j * nx + i] + dery_bh[j * nx + i]*dery_bh[j * nx + i] ))+
423 err_termAh[j * nx + i] / (16.0*( derx_bh[j * nx + i]*derx_bh[j * nx + i] + dery_bh[j * nx + i]*dery_bh[j * nx + i] )) ;
424 count_mask++;
425 }
426 }
427
428 *mean_derivative_bh_ptr = (sum)/(count_mask); // would be divided by ((nx-2)*(ny-2)) if shape of count_mask = shape of magnetogram
429 *mean_derivative_bh_err_ptr = (sqrt(err))/(count_mask); // error in the quantity (sum)/(count_mask)
430 //printf("MEANGBH=%f\n",*mean_derivative_bh_ptr);
431 //printf("MEANGBH_err=%f\n",*mean_derivative_bh_err_ptr);
432
433 return 0;
434 }
435
436 /*===========================================*/
437 /* Example function 7: Derivative of B_vertical SQRT( (dBz/dx)^2 + (dBz/dy)^2 ) */
438
439 int computeBzderivative(float *bz, float *bz_err, int *dims, float *mean_derivative_bz_ptr, float *mean_derivative_bz_err_ptr, int *mask, int *bitmask, float *derx_bz, float *dery_bz, float *err_termA, float *err_termB)
440 {
441
442 int nx = dims[0];
443 int ny = dims[1];
444 int i = 0;
445 int j = 0;
446 int count_mask = 0;
447 double sum = 0.0;
448 double err = 0.0;
449 *mean_derivative_bz_ptr = 0.0;
450
451 if (nx <= 0 || ny <= 0) return 1;
452
453 /* brute force method of calculating the derivative (no consideration for edges) */
454 for (i = 1; i <= nx-2; i++)
455 {
456 for (j = 0; j <= ny-1; j++)
457 {
458 derx_bz[j * nx + i] = (bz[j * nx + i+1] - bz[j * nx + i-1])*0.5;
459 err_termA[j * nx + i] = (((bz[j * nx + (i+1)]-bz[j * nx + (i-1)])*(bz[j * nx + (i+1)]-bz[j * nx + (i-1)])) * (bz_err[j * nx + (i+1)]*bz_err[j * nx + (i+1)] + bz_err[j * nx + (i-1)]*bz_err[j * nx + (i-1)]));
460 }
461 }
462
463 /* brute force method of calculating the derivative (no consideration for edges) */
464 for (i = 0; i <= nx-1; i++)
465 {
466 for (j = 1; j <= ny-2; j++)
467 {
468 dery_bz[j * nx + i] = (bz[(j+1) * nx + i] - bz[(j-1) * nx + i])*0.5;
469 err_termB[j * nx + i] = (((bz[(j+1) * nx + i]-bz[(j-1) * nx + i])*(bz[(j+1) * nx + i]-bz[(j-1) * nx + i])) * (bz_err[(j+1) * nx + i]*bz_err[(j+1) * nx + i] + bz_err[(j-1) * nx + i]*bz_err[(j-1) * nx + i]));
470 }
471 }
472
473 /* consider the edges for the arrays that contribute to the variable "sum" in the computation below.
474 ignore the edges for the error terms as those arrays have been initialized to zero.
475 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.*/
476 i=0;
477 for (j = 0; j <= ny-1; j++)
478 {
479 derx_bz[j * nx + i] = ( (-3*bz[j * nx + i]) + (4*bz[j * nx + (i+1)]) - (bz[j * nx + (i+2)]) )*0.5;
480 }
481
482 i=nx-1;
483 for (j = 0; j <= ny-1; j++)
484 {
485 derx_bz[j * nx + i] = ( (3*bz[j * nx + i]) + (-4*bz[j * nx + (i-1)]) - (-bz[j * nx + (i-2)]) )*0.5;
486 }
487
488 j=0;
489 for (i = 0; i <= nx-1; i++)
490 {
491 dery_bz[j * nx + i] = ( (-3*bz[j*nx + i]) + (4*bz[(j+1) * nx + i]) - (bz[(j+2) * nx + i]) )*0.5;
492 }
493
494 j=ny-1;
495 for (i = 0; i <= nx-1; i++)
496 {
497 dery_bz[j * nx + i] = ( (3*bz[j * nx + i]) + (-4*bz[(j-1) * nx + i]) - (-bz[(j-2) * nx + i]) )*0.5;
498 }
499
500
501 for (i = 0; i <= nx-1; i++)
502 {
503 for (j = 0; j <= ny-1; j++)
504 {
505 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
506 if ( (derx_bz[j * nx + i] + dery_bz[j * nx + i]) == 0) continue;
507 if isnan(bz[j * nx + i]) continue;
508 if isnan(bz[(j+1) * nx + i]) continue;
509 if isnan(bz[(j-1) * nx + i]) continue;
510 if isnan(bz[j * nx + i-1]) continue;
511 if isnan(bz[j * nx + i+1]) continue;
512 if isnan(bz_err[j * nx + i]) continue;
513 if isnan(derx_bz[j * nx + i]) continue;
514 if isnan(dery_bz[j * nx + i]) continue;
515 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 */
516 err += err_termB[j * nx + i] / (16.0*( derx_bz[j * nx + i]*derx_bz[j * nx + i] + dery_bz[j * nx + i]*dery_bz[j * nx + i] )) +
517 err_termA[j * nx + i] / (16.0*( derx_bz[j * nx + i]*derx_bz[j * nx + i] + dery_bz[j * nx + i]*dery_bz[j * nx + i] )) ;
518 count_mask++;
519 }
520 }
521
522 *mean_derivative_bz_ptr = (sum)/(count_mask); // would be divided by ((nx-2)*(ny-2)) if shape of count_mask = shape of magnetogram
523 *mean_derivative_bz_err_ptr = (sqrt(err))/(count_mask); // error in the quantity (sum)/(count_mask)
524 //printf("MEANGBZ=%f\n",*mean_derivative_bz_ptr);
525 //printf("MEANGBZ_err=%f\n",*mean_derivative_bz_err_ptr);
526
527 return 0;
528 }
529
530 /*===========================================*/
531 /* Example function 8: Current Jz = (dBy/dx) - (dBx/dy) */
532
533 // In discretized space like data pixels,
534 // the current (or curl of B) is calculated as
535 // the integration of the field Bx and By along
536 // the circumference of the data pixel divided by the area of the pixel.
537 // One form of differencing (a word for the differential operator
538 // in the discretized space) of the curl is expressed as
539 // (dx * (Bx(i,j-1)+Bx(i,j)) / 2
540 // +dy * (By(i+1,j)+By(i,j)) / 2
541 // -dx * (Bx(i,j+1)+Bx(i,j)) / 2
542 // -dy * (By(i-1,j)+By(i,j)) / 2) / (dx * dy)
543 //
544 //
545 // To change units from Gauss/pixel to mA/m^2 (the units for Jz in Leka and Barnes, 2003),
546 // one must perform the following unit conversions:
547 // (Gauss)(1/arcsec)(arcsec/meter)(Newton/Gauss*Ampere*meter)(Ampere^2/Newton)(milliAmpere/Ampere), or
548 // (Gauss)(1/CDELT1)(RSUN_OBS/RSUN_REF)(1 T / 10^4 Gauss)(1 / 4*PI*10^-7)( 10^3 milliAmpere/Ampere), or
549 // (Gauss)(1/CDELT1)(RSUN_OBS/RSUN_REF)(0.00010)(1/MUNAUGHT)(1000.),
550 // where a Tesla is represented as a Newton/Ampere*meter.
551 //
552 // As an order of magnitude estimate, we can assign 0.5 to CDELT1 and 722500m/arcsec to (RSUN_REF/RSUN_OBS).
553 // In that case, we would have the following:
554 // (Gauss/pix)(1/0.5)(1/722500)(10^-4)(4*PI*10^7)(10^3), or
555 // jz * (35.0)
556 //
557 // The units of total unsigned vertical current (us_i) are simply in A. In this case, we would have the following:
558 // (Gauss/pix)(1/CDELT1)(RSUN_OBS/RSUN_REF)(0.00010)(1/MUNAUGHT)(CDELT1)(CDELT1)(RSUN_REF/RSUN_OBS)(RSUN_REF/RSUN_OBS)
559 // = (Gauss/pix)(0.00010)(1/MUNAUGHT)(CDELT1)(RSUN_REF/RSUN_OBS)
560
561
562 // Comment out random number generator, which can only run on solar3
563 // int computeJz(float *bx_err, float *by_err, float *bx, float *by, int *dims, float *jz, float *jz_err, float *jz_err_squared,
564 // int *mask, int *bitmask, float cdelt1, double rsun_ref, double rsun_obs,float *derx, float *dery, float *noisebx,
565 // float *noiseby, float *noisebz)
566
567 int computeJz(float *bx_err, float *by_err, float *bx, float *by, int *dims, float *jz, float *jz_err, float *jz_err_squared,
568 int *mask, int *bitmask, float cdelt1, double rsun_ref, double rsun_obs,float *derx, float *dery, float *err_term1, float *err_term2)
569
570
571 {
572 int nx = dims[0];
573 int ny = dims[1];
574 int i = 0;
575 int j = 0;
576 int count_mask = 0;
577
578 if (nx <= 0 || ny <= 0) return 1;
579
580 /* Calculate the derivative*/
581 /* brute force method of calculating the derivative (no consideration for edges) */
582
583 for (i = 1; i <= nx-2; i++)
584 {
585 for (j = 0; j <= ny-1; j++)
586 {
587 derx[j * nx + i] = (by[j * nx + i+1] - by[j * nx + i-1])*0.5;
588 err_term1[j * nx + i] = (by_err[j * nx + i+1])*(by_err[j * nx + i+1]) + (by_err[j * nx + i-1])*(by_err[j * nx + i-1]);
589 }
590 }
591
592 for (i = 0; i <= nx-1; i++)
593 {
594 for (j = 1; j <= ny-2; j++)
595 {
596 dery[j * nx + i] = (bx[(j+1) * nx + i] - bx[(j-1) * nx + i])*0.5;
597 err_term2[j * nx + i] = (bx_err[(j+1) * nx + i])*(bx_err[(j+1) * nx + i]) + (bx_err[(j-1) * nx + i])*(bx_err[(j-1) * nx + i]);
598 }
599 }
600
601 /* consider the edges for the arrays that contribute to the variable "sum" in the computation below.
602 ignore the edges for the error terms as those arrays have been initialized to zero.
603 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.*/
604
605 i=0;
606 for (j = 0; j <= ny-1; j++)
607 {
608 derx[j * nx + i] = ( (-3*by[j * nx + i]) + (4*by[j * nx + (i+1)]) - (by[j * nx + (i+2)]) )*0.5;
609 }
610
611 i=nx-1;
612 for (j = 0; j <= ny-1; j++)
613 {
614 derx[j * nx + i] = ( (3*by[j * nx + i]) + (-4*by[j * nx + (i-1)]) - (-by[j * nx + (i-2)]) )*0.5;
615 }
616
617 j=0;
618 for (i = 0; i <= nx-1; i++)
619 {
620 dery[j * nx + i] = ( (-3*bx[j*nx + i]) + (4*bx[(j+1) * nx + i]) - (bx[(j+2) * nx + i]) )*0.5;
621 }
622
623 j=ny-1;
624 for (i = 0; i <= nx-1; i++)
625 {
626 dery[j * nx + i] = ( (3*bx[j * nx + i]) + (-4*bx[(j-1) * nx + i]) - (-bx[(j-2) * nx + i]) )*0.5;
627 }
628
629
630 for (i = 0; i <= nx-1; i++)
631 {
632 for (j = 0; j <= ny-1; j++)
633 {
634 // calculate jz at all points
635 jz[j * nx + i] = (derx[j * nx + i]-dery[j * nx + i]); // jz is in units of Gauss/pix
636 jz_err[j * nx + i] = 0.5*sqrt( err_term1[j * nx + i] + err_term2[j * nx + i] ) ;
637 jz_err_squared[j * nx + i]= (jz_err[j * nx + i]*jz_err[j * nx + i]);
638 count_mask++;
639 }
640 }
641 return 0;
642 }
643
644 /*===========================================*/
645
646 /* Example function 9: Compute quantities on Jz array */
647 // Compute mean and total current on Jz array.
648
649 int computeJzsmooth(float *bx, float *by, int *dims, float *jz, float *jz_smooth, float *jz_err, float *jz_rms_err, float *jz_err_squared_smooth,
650 float *mean_jz_ptr, float *mean_jz_err_ptr, float *us_i_ptr, float *us_i_err_ptr, int *mask, int *bitmask,
651 float cdelt1, double rsun_ref, double rsun_obs,float *derx, float *dery)
652
653 {
654
655 int nx = dims[0];
656 int ny = dims[1];
657 int i = 0;
658 int j = 0;
659 int count_mask = 0;
660 double curl = 0.0;
661 double us_i = 0.0;
662 double err = 0.0;
663
664 if (nx <= 0 || ny <= 0) return 1;
665
666 /* At this point, use the smoothed Jz array with a Gaussian (FWHM of 4 pix and truncation width of 12 pixels) but keep the original array dimensions*/
667 for (i = 0; i <= nx-1; i++)
668 {
669 for (j = 0; j <= ny-1; j++)
670 {
671 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
672 if isnan(derx[j * nx + i]) continue;
673 if isnan(dery[j * nx + i]) continue;
674 if isnan(jz[j * nx + i]) continue;
675 curl += (jz[j * nx + i])*(1/cdelt1)*(rsun_obs/rsun_ref)*(0.00010)*(1/MUNAUGHT)*(1000.); /* curl is in units of mA / m^2 */
676 us_i += fabs(jz[j * nx + i])*(cdelt1/1)*(rsun_ref/rsun_obs)*(0.00010)*(1/MUNAUGHT); /* us_i is in units of A */
677 err += (jz_err[j * nx + i]*jz_err[j * nx + i]);
678 count_mask++;
679 }
680 }
681
682 /* Calculate mean vertical current density (mean_jz) and total unsigned vertical current (us_i) using smoothed Jz array and continue conditions above */
683 *mean_jz_ptr = curl/(count_mask); /* mean_jz gets populated as MEANJZD */
684 *mean_jz_err_ptr = (sqrt(err)/count_mask)*((1/cdelt1)*(rsun_obs/rsun_ref)*(0.00010)*(1/MUNAUGHT)*(1000.)); // error in the quantity MEANJZD
685
686 *us_i_ptr = (us_i); /* us_i gets populated as TOTUSJZ */
687 *us_i_err_ptr = (sqrt(err))*((cdelt1/1)*(rsun_ref/rsun_obs)*(0.00010)*(1/MUNAUGHT)); // error in the quantity TOTUSJZ
688
689 //printf("MEANJZD=%f\n",*mean_jz_ptr);
690 //printf("MEANJZD_err=%f\n",*mean_jz_err_ptr);
691
692 //printf("TOTUSJZ=%g\n",*us_i_ptr);
693 //printf("TOTUSJZ_err=%g\n",*us_i_err_ptr);
694
695 return 0;
696
697 }
698
699 /*===========================================*/
700
701 /* Example function 10: Twist Parameter, alpha */
702
703 // The twist parameter, alpha, is defined as alpha = Jz/Bz. In this case, the calculation
704 // for alpha is weighted by Bz (following Hagino et al., http://adsabs.harvard.edu/abs/2004PASJ...56..831H):
705
706 // numerator = sum of all Jz*Bz
707 // denominator = sum of Bz*Bz
708 // alpha = numerator/denominator
709
710 // The units of alpha are in 1/Mm
711 // The units of Jz are in Gauss/pix; the units of Bz are in Gauss.
712 //
713 // Therefore, the units of Jz/Bz = (Gauss/pix)(1/Gauss)(pix/arcsec)(arsec/meter)(meter/Mm), or
714 // = (Gauss/pix)(1/Gauss)(1/CDELT1)(RSUN_OBS/RSUN_REF)(10^6)
715 // = 1/Mm
716
717 int computeAlpha(float *jz_err, float *bz_err, float *bz, int *dims, float *jz, float *jz_smooth, float *mean_alpha_ptr, float *mean_alpha_err_ptr, int *mask, int *bitmask, float cdelt1, double rsun_ref, double rsun_obs)
718
719 {
720 int nx = dims[0];
721 int ny = dims[1];
722 int i = 0;
723 int j = 0;
724 double alpha_total = 0.0;
725 double C = ((1/cdelt1)*(rsun_obs/rsun_ref)*(1000000.));
726 double total = 0.0;
727 double A = 0.0;
728 double B = 0.0;
729
730 if (nx <= 0 || ny <= 0) return 1;
731 for (i = 1; i < nx-1; i++)
732 {
733 for (j = 1; j < ny-1; j++)
734 {
735 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
736 if isnan(jz[j * nx + i]) continue;
737 if isnan(bz[j * nx + i]) continue;
738 if (jz[j * nx + i] == 0.0) continue;
739 if (bz[j * nx + i] == 0.0) continue;
740 A += jz[j*nx+i]*bz[j*nx+i];
741 B += bz[j*nx+i]*bz[j*nx+i];
742 }
743 }
744
745 for (i = 1; i < nx-1; i++)
746 {
747 for (j = 1; j < ny-1; j++)
748 {
749 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
750 if isnan(jz[j * nx + i]) continue;
751 if isnan(bz[j * nx + i]) continue;
752 if (jz[j * nx + i] == 0.0) continue;
753 if (bz[j * nx + i] == 0.0) continue;
754 total += bz[j*nx+i]*bz[j*nx+i]*jz_err[j*nx+i]*jz_err[j*nx+i] + (jz[j*nx+i]-2*bz[j*nx+i]*A/B)*(jz[j*nx+i]-2*bz[j*nx+i]*A/B)*bz_err[j*nx+i]*bz_err[j*nx+i];
755 }
756 }
757
758 /* Determine the absolute value of alpha. The units for alpha are 1/Mm */
759 alpha_total = ((A/B)*C);
760 *mean_alpha_ptr = alpha_total;
761 *mean_alpha_err_ptr = (C/B)*(sqrt(total));
762
763 return 0;
764 }
765
766 /*===========================================*/
767 /* Example function 11: Helicity (mean current helicty, total unsigned current helicity, absolute value of net current helicity) */
768
769 // The current helicity is defined as Bz*Jz and the units are G^2 / m
770 // The units of Jz are in G/pix; the units of Bz are in G.
771 // Therefore, the units of Bz*Jz = (Gauss)*(Gauss/pix) = (Gauss^2/pix)(pix/arcsec)(arcsec/meter)
772 // = (Gauss^2/pix)(1/CDELT1)(RSUN_OBS/RSUN_REF)
773 // = G^2 / m.
774
775 int computeHelicity(float *jz_err, float *jz_rms_err, float *bz_err, float *bz, int *dims, float *jz, float *mean_ih_ptr,
776 float *mean_ih_err_ptr, float *total_us_ih_ptr, float *total_abs_ih_ptr,
777 float *total_us_ih_err_ptr, float *total_abs_ih_err_ptr, int *mask, int *bitmask, float cdelt1, double rsun_ref, double rsun_obs)
778
779 {
780
781 int nx = dims[0];
782 int ny = dims[1];
783 int i = 0;
784 int j = 0;
785 int count_mask = 0;
786 double sum = 0.0;
787 double sum2 = 0.0;
788 double err = 0.0;
789
790 if (nx <= 0 || ny <= 0) return 1;
791
792 for (i = 0; i < nx; i++)
793 {
794 for (j = 0; j < ny; j++)
795 {
796 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
797 if isnan(jz[j * nx + i]) continue;
798 if isnan(bz[j * nx + i]) continue;
799 if isnan(jz_err[j * nx + i]) continue;
800 if isnan(bz_err[j * nx + i]) continue;
801 if (bz[j * nx + i] == 0.0) continue;
802 if (jz[j * nx + i] == 0.0) continue;
803 sum += (jz[j * nx + i]*bz[j * nx + i])*(1/cdelt1)*(rsun_obs/rsun_ref); // contributes to MEANJZH and ABSNJZH
804 sum2 += fabs(jz[j * nx + i]*bz[j * nx + i])*(1/cdelt1)*(rsun_obs/rsun_ref); // contributes to TOTUSJH
805 err += (jz_err[j * nx + i]*jz_err[j * nx + i]*bz[j * nx + i]*bz[j * nx + i]) + (bz_err[j * nx + i]*bz_err[j * nx + i]*jz[j * nx + i]*jz[j * nx + i]);
806 count_mask++;
807 }
808 }
809
810 *mean_ih_ptr = sum/count_mask ; /* Units are G^2 / m ; keyword is MEANJZH */
811 *total_us_ih_ptr = sum2 ; /* Units are G^2 / m ; keyword is TOTUSJH */
812 *total_abs_ih_ptr = fabs(sum) ; /* Units are G^2 / m ; keyword is ABSNJZH */
813
814 *mean_ih_err_ptr = (sqrt(err)/count_mask)*(1/cdelt1)*(rsun_obs/rsun_ref) ; // error in the quantity MEANJZH
815 *total_us_ih_err_ptr = (sqrt(err))*(1/cdelt1)*(rsun_obs/rsun_ref) ; // error in the quantity TOTUSJH
816 *total_abs_ih_err_ptr = (sqrt(err))*(1/cdelt1)*(rsun_obs/rsun_ref) ; // error in the quantity ABSNJZH
817
818 //printf("MEANJZH=%f\n",*mean_ih_ptr);
819 //printf("MEANJZH_err=%f\n",*mean_ih_err_ptr);
820
821 //printf("TOTUSJH=%f\n",*total_us_ih_ptr);
822 //printf("TOTUSJH_err=%f\n",*total_us_ih_err_ptr);
823
824 //printf("ABSNJZH=%f\n",*total_abs_ih_ptr);
825 //printf("ABSNJZH_err=%f\n",*total_abs_ih_err_ptr);
826
827 return 0;
828 }
829
830 /*===========================================*/
831 /* Example function 12: Sum of Absolute Value per polarity */
832
833 // The Sum of the Absolute Value per polarity is defined as the following:
834 // fabs(sum(jz gt 0)) + fabs(sum(jz lt 0)) and the units are in Amperes per square arcsecond.
835 // The units of jz are in G/pix. In this case, we would have the following:
836 // Jz = (Gauss/pix)(1/CDELT1)(0.00010)(1/MUNAUGHT)(RSUN_REF/RSUN_OBS)(RSUN_REF/RSUN_OBS)(RSUN_OBS/RSUN_REF),
837 // = (Gauss/pix)(1/CDELT1)(0.00010)(1/MUNAUGHT)(RSUN_REF/RSUN_OBS)
838 //
839 // The error in this quantity is the same as the error in the mean vertical current (mean_jz_err).
840
841 int computeSumAbsPerPolarity(float *jz_err, float *bz_err, float *bz, float *jz, int *dims, float *totaljzptr, float *totaljz_err_ptr,
842 int *mask, int *bitmask, float cdelt1, double rsun_ref, double rsun_obs)
843
844 {
845 int nx = dims[0];
846 int ny = dims[1];
847 int i=0;
848 int j=0;
849 int count_mask=0;
850 double sum1=0.0;
851 double sum2=0.0;
852 double err=0.0;
853 *totaljzptr=0.0;
854
855 if (nx <= 0 || ny <= 0) return 1;
856
857 for (i = 0; i < nx; i++)
858 {
859 for (j = 0; j < ny; j++)
860 {
861 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
862 if isnan(bz[j * nx + i]) continue;
863 if isnan(jz[j * nx + i]) continue;
864 if (bz[j * nx + i] > 0) sum1 += ( jz[j * nx + i])*(1/cdelt1)*(0.00010)*(1/MUNAUGHT)*(rsun_ref/rsun_obs);
865 if (bz[j * nx + i] <= 0) sum2 += ( jz[j * nx + i])*(1/cdelt1)*(0.00010)*(1/MUNAUGHT)*(rsun_ref/rsun_obs);
866 err += (jz_err[j * nx + i]*jz_err[j * nx + i]);
867 count_mask++;
868 }
869 }
870
871 *totaljzptr = fabs(sum1) + fabs(sum2); /* Units are Amperes per arcsecond */
872 *totaljz_err_ptr = sqrt(err)*(1/cdelt1)*fabs((0.00010)*(1/MUNAUGHT)*(rsun_ref/rsun_obs));
873 //printf("SAVNCPP=%g\n",*totaljzptr);
874 //printf("SAVNCPP_err=%g\n",*totaljz_err_ptr);
875
876 return 0;
877 }
878
879 /*===========================================*/
880 /* Example function 13: Mean photospheric excess magnetic energy and total photospheric excess magnetic energy density */
881 // The units for magnetic energy density in cgs are ergs per cubic centimeter. The formula B^2/8*PI integrated over all space, dV
882 // automatically yields erg per cubic centimeter for an input B in Gauss. Note that the 8*PI can come out of the integral; thus,
883 // the integral is over B^2 dV and the 8*PI is divided at the end.
884 //
885 // Total magnetic energy is the magnetic energy density times dA, or the area, and the units are thus ergs/cm. To convert
886 // ergs per centimeter cubed to ergs per centimeter, simply multiply by the area per pixel in cm:
887 // erg/cm^3*(CDELT1^2)*(RSUN_REF/RSUN_OBS ^2)*(100.^2)
888 // = erg/cm^3*(0.5 arcsec/pix)^2(722500m/arcsec)^2(100cm/m)^2
889 // = erg/cm^3*(1.30501e15)
890 // = erg/cm(1/pix^2)
891
892 int computeFreeEnergy(float *bx_err, float *by_err, float *bx, float *by, float *bpx, float *bpy, int *dims,
893 float *meanpotptr, float *meanpot_err_ptr, float *totpotptr, float *totpot_err_ptr, int *mask, int *bitmask,
894 float cdelt1, double rsun_ref, double rsun_obs)
895
896 {
897 int nx = dims[0];
898 int ny = dims[1];
899 int i = 0;
900 int j = 0;
901 int count_mask = 0;
902 double sum = 0.0;
903 double sum1 = 0.0;
904 double err = 0.0;
905 *totpotptr = 0.0;
906 *meanpotptr = 0.0;
907
908 if (nx <= 0 || ny <= 0) return 1;
909
910 for (i = 0; i < nx; i++)
911 {
912 for (j = 0; j < ny; j++)
913 {
914 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
915 if isnan(bx[j * nx + i]) continue;
916 if isnan(by[j * nx + i]) continue;
917 sum += ( ((bx[j * nx + i] - bpx[j * nx + i])*(bx[j * nx + i] - bpx[j * nx + i])) + ((by[j * nx + i] - bpy[j * nx + i])*(by[j * nx + i] - bpy[j * nx + i])) )*(cdelt1*cdelt1*(rsun_ref/rsun_obs)*(rsun_ref/rsun_obs)*100.0*100.0);
918 sum1 += ( ((bx[j * nx + i] - bpx[j * nx + i])*(bx[j * nx + i] - bpx[j * nx + i])) + ((by[j * nx + i] - bpy[j * nx + i])*(by[j * nx + i] - bpy[j * nx + i])) );
919 err += 4.0*(bx[j * nx + i] - bpx[j * nx + i])*(bx[j * nx + i] - bpx[j * nx + i])*(bx_err[j * nx + i]*bx_err[j * nx + i]) +
920 4.0*(by[j * nx + i] - bpy[j * nx + i])*(by[j * nx + i] - bpy[j * nx + i])*(by_err[j * nx + i]*by_err[j * nx + i]);
921 count_mask++;
922 }
923 }
924
925 /* Units of meanpotptr are ergs per centimeter */
926 *meanpotptr = (sum1) / (count_mask*8.*PI) ; /* Units are ergs per cubic centimeter */
927 *meanpot_err_ptr = (sqrt(err)) / (count_mask*8.*PI); // error in the quantity (sum)/(count_mask)
928
929 /* Units of sum are ergs/cm^3, units of factor are cm^2/pix^2; therefore, units of totpotptr are ergs per centimeter */
930 *totpotptr = (sum)/(8.*PI);
931 *totpot_err_ptr = (sqrt(err))*fabs(cdelt1*cdelt1*(rsun_ref/rsun_obs)*(rsun_ref/rsun_obs)*100.0*100.0*(1/(8.*PI)));
932
933 //printf("MEANPOT=%g\n",*meanpotptr);
934 //printf("MEANPOT_err=%g\n",*meanpot_err_ptr);
935
936 //printf("TOTPOT=%g\n",*totpotptr);
937 //printf("TOTPOT_err=%g\n",*totpot_err_ptr);
938
939 return 0;
940 }
941
942 /*===========================================*/
943 /* Example function 14: Mean 3D shear angle, area with shear greater than 45, mean horizontal shear angle, area with horizontal shear angle greater than 45 */
944
945 int computeShearAngle(float *bx_err, float *by_err, float *bz_err, float *bx, float *by, float *bz, float *bpx, float *bpy, float *bpz, int *dims,
946 float *meanshear_angleptr, float *meanshear_angle_err_ptr, float *area_w_shear_gt_45ptr, int *mask, int *bitmask)
947
948
949 {
950 int nx = dims[0];
951 int ny = dims[1];
952 int i = 0;
953 int j = 0;
954 float count_mask = 0;
955 float count = 0;
956 double dotproduct = 0.0;
957 double magnitude_potential = 0.0;
958 double magnitude_vector = 0.0;
959 double shear_angle = 0.0;
960 double denominator = 0.0;
961 double term1 = 0.0;
962 double term2 = 0.0;
963 double term3 = 0.0;
964 double sumsum = 0.0;
965 double err = 0.0;
966 double part1 = 0.0;
967 double part2 = 0.0;
968 double part3 = 0.0;
969 *area_w_shear_gt_45ptr = 0.0;
970 *meanshear_angleptr = 0.0;
971
972 if (nx <= 0 || ny <= 0) return 1;
973
974 for (i = 0; i < nx; i++)
975 {
976 for (j = 0; j < ny; j++)
977 {
978 if ( mask[j * nx + i] < 70 || bitmask[j * nx + i] < 30 ) continue;
979 if isnan(bpx[j * nx + i]) continue;
980 if isnan(bpy[j * nx + i]) continue;
981 if isnan(bpz[j * nx + i]) continue;
982 if isnan(bz[j * nx + i]) continue;
983 if isnan(bx[j * nx + i]) continue;
984 if isnan(by[j * nx + i]) continue;
985 if isnan(bx_err[j * nx + i]) continue;
986 if isnan(by_err[j * nx + i]) continue;
987 if isnan(bz_err[j * nx + i]) continue;
988
989 /* For mean 3D shear angle, percentage with shear greater than 45*/
990 dotproduct = (bpx[j * nx + i])*(bx[j * nx + i]) + (bpy[j * nx + i])*(by[j * nx + i]) + (bpz[j * nx + i])*(bz[j * nx + i]);
991 magnitude_potential = sqrt( (bpx[j * nx + i]*bpx[j * nx + i]) + (bpy[j * nx + i]*bpy[j * nx + i]) + (bpz[j * nx + i]*bpz[j * nx + i]));
992 magnitude_vector = sqrt( (bx[j * nx + i]*bx[j * nx + i]) + (by[j * nx + i]*by[j * nx + i]) + (bz[j * nx + i]*bz[j * nx + i]) );
993 //printf("dotproduct=%f\n",dotproduct);
994 //printf("magnitude_potential=%f\n",magnitude_potential);
995 //printf("magnitude_vector=%f\n",magnitude_vector);
996
997 shear_angle = acos(dotproduct/(magnitude_potential*magnitude_vector))*(180./PI);
998 sumsum += shear_angle;
999 //printf("shear_angle=%f\n",shear_angle);
1000 count ++;
1001
1002 if (shear_angle > 45) count_mask ++;
1003
1004 // For the error analysis
1005
1006 term1 = bx[j * nx + i]*by[j * nx + i]*bpy[j * nx + i] - by[j * nx + i]*by[j * nx + i]*bpx[j * nx + i] + bz[j * nx + i]*bx[j * nx + i]*bpz[j * nx + i] - bz[j * nx + i]*bz[j * nx + i]*bpx[j * nx + i];
1007 term2 = bx[j * nx + i]*bx[j * nx + i]*bpy[j * nx + i] - bx[j * nx + i]*by[j * nx + i]*bpx[j * nx + i] + bx[j * nx + i]*bz[j * nx + i]*bpy[j * nx + i] - bz[j * nx + i]*by[j * nx + i]*bpz[j * nx + i];
1008 term3 = bx[j * nx + i]*bx[j * nx + i]*bpz[j * nx + i] - bx[j * nx + i]*bz[j * nx + i]*bpx[j * nx + i] + by[j * nx + i]*by[j * nx + i]*bpz[j * nx + i] - by[j * nx + i]*bz[j * nx + i]*bpy[j * nx + i];
1009
1010 part1 = bx[j * nx + i]*bx[j * nx + i] + by[j * nx + i]*by[j * nx + i] + bz[j * nx + i]*bz[j * nx + i];
1011 part2 = bpx[j * nx + i]*bpx[j * nx + i] + bpy[j * nx + i]*bpy[j * nx + i] + bpz[j * nx + i]*bpz[j * nx + i];
1012 part3 = bx[j * nx + i]*bpx[j * nx + i] + by[j * nx + i]*bpy[j * nx + i] + bz[j * nx + i]*bpz[j * nx + i];
1013
1014 // denominator is squared
1015 denominator = part1*part1*part1*part2*(1.0-((part3*part3)/(part1*part2)));
1016
1017 err = (term1*term1*bx_err[j * nx + i]*bx_err[j * nx + i])/(denominator) +
1018 (term1*term1*bx_err[j * nx + i]*bx_err[j * nx + i])/(denominator) +
1019 (term1*term1*bx_err[j * nx + i]*bx_err[j * nx + i])/(denominator) ;
1020
1021 }
1022 }
1023 /* For mean 3D shear angle, area with shear greater than 45*/
1024 *meanshear_angleptr = (sumsum)/(count); /* Units are degrees */
1025 *meanshear_angle_err_ptr = (sqrt(err)/count_mask)*(180./PI);
1026
1027 /* The area here is a fractional area -- the % of the total area. This has no error associated with it. */
1028 *area_w_shear_gt_45ptr = (count_mask/(count))*(100.0);
1029
1030 //printf("MEANSHR=%f\n",*meanshear_angleptr);
1031 //printf("MEANSHR_err=%f\n",*meanshear_angle_err_ptr);
1032 //printf("SHRGT45=%f\n",*area_w_shear_gt_45ptr);
1033
1034 return 0;
1035 }
1036
1037 /*===========================================*/
1038 /* Example function 15: R parameter as defined in Schrijver, 2007 */
1039 //
1040 // Note that there is a restriction on the function fsample()
1041 // If the following occurs:
1042 // nx_out > floor((ny_in-1)/scale + 1)
1043 // ny_out > floor((ny_in-1)/scale + 1),
1044 // where n*_out are the dimensions of the output array and n*_in
1045 // are the dimensions of the input array, fsample() will usually result
1046 // in a segfault (though not always, depending on how the segfault was accessed.)
1047
1048 int computeR(float *bz_err, float *los, int *dims, float *Rparam, float cdelt1,
1049 float *rim, float *p1p0, float *p1n0, float *p1p, float *p1n, float *p1,
1050 float *pmap, int nx1, int ny1,
1051 int scale, float *p1pad, int nxp, int nyp, float *pmapn)
1052
1053 {
1054 int nx = dims[0];
1055 int ny = dims[1];
1056 int i = 0;
1057 int j = 0;
1058 int index, index1;
1059 double sum = 0.0;
1060 double err = 0.0;
1061 *Rparam = 0.0;
1062 struct fresize_struct fresboxcar, fresgauss;
1063 struct fint_struct fints;
1064 float sigma = 10.0/2.3548;
1065
1066 // set up convolution kernels
1067 init_fresize_boxcar(&fresboxcar,1,1);
1068 init_fresize_gaussian(&fresgauss,sigma,20,1);
1069
1070 // =============== [STEP 1] ===============
1071 // bin the line-of-sight magnetogram down by a factor of scale
1072 fsample(los, rim, nx, ny, nx, nx1, ny1, nx1, scale, 0, 0, 0.0);
1073
1074 // =============== [STEP 2] ===============
1075 // identify positive and negative pixels greater than +/- 150 gauss
1076 // and label those pixels with a 1.0 in arrays p1p0 and p1n0
1077 for (i = 0; i < nx1; i++)
1078 {
1079 for (j = 0; j < ny1; j++)
1080 {
1081 index = j * nx1 + i;
1082 if (rim[index] > 150)
1083 p1p0[index]=1.0;
1084 else
1085 p1p0[index]=0.0;
1086 if (rim[index] < -150)
1087 p1n0[index]=1.0;
1088 else
1089 p1n0[index]=0.0;
1090 }
1091 }
1092
1093 // =============== [STEP 3] ===============
1094 // smooth each of the negative and positive pixel bitmaps
1095 fresize(&fresboxcar, p1p0, p1p, nx1, ny1, nx1, nx1, ny1, nx1, 0, 0, 0.0);
1096 fresize(&fresboxcar, p1n0, p1n, nx1, ny1, nx1, nx1, ny1, nx1, 0, 0, 0.0);
1097
1098 // =============== [STEP 4] ===============
1099 // find the pixels for which p1p and p1n are both equal to 1.
1100 // this defines the polarity inversion line
1101 for (i = 0; i < nx1; i++)
1102 {
1103 for (j = 0; j < ny1; j++)
1104 {
1105 index = j * nx1 + i;
1106 if ((p1p[index] > 0.0) && (p1n[index] > 0.0))
1107 p1[index]=1.0;
1108 else
1109 p1[index]=0.0;
1110 }
1111 }
1112
1113 // pad p1 with zeroes so that the gaussian colvolution in step 5
1114 // does not cut off data within hwidth of the edge
1115
1116 // step i: zero p1pad
1117 for (i = 0; i < nxp; i++)
1118 {
1119 for (j = 0; j < nyp; j++)
1120 {
1121 index = j * nxp + i;
1122 p1pad[index]=0.0;
1123 }
1124 }
1125
1126 // step ii: place p1 at the center of p1pad
1127 for (i = 0; i < nx1; i++)
1128 {
1129 for (j = 0; j < ny1; j++)
1130 {
1131 index = j * nx1 + i;
1132 index1 = (j+20) * nxp + (i+20);
1133 p1pad[index1]=p1[index];
1134 }
1135 }
1136
1137 // =============== [STEP 5] ===============
1138 // convolve the polarity inversion line map with a gaussian
1139 // to identify the region near the plarity inversion line
1140 // the resultant array is called pmap
1141 fresize(&fresgauss, p1pad, pmap, nxp, nyp, nxp, nxp, nyp, nxp, 0, 0, 0.0);
1142
1143
1144 // select out the nx1 x ny1 non-padded array within pmap
1145 for (i = 0; i < nx1; i++)
1146 {
1147 for (j = 0; j < ny1; j++)
1148 {
1149 index = j * nx1 + i;
1150 index1 = (j+20) * nxp + (i+20);
1151 pmapn[index]=pmap[index1];
1152 }
1153 }
1154
1155 // =============== [STEP 6] ===============
1156 // the R parameter is calculated
1157 for (i = 0; i < nx1; i++)
1158 {
1159 for (j = 0; j < ny1; j++)
1160 {
1161 index = j * nx1 + i;
1162 if isnan(pmapn[index]) continue;
1163 if isnan(rim[index]) continue;
1164 sum += pmapn[index]*abs(rim[index]);
1165 }
1166 }
1167
1168 if (sum < 1.0)
1169 *Rparam = 0.0;
1170 else
1171 *Rparam = log10(sum);
1172
1173 //printf("R_VALUE=%f\n",*Rparam);
1174
1175 free_fresize(&fresboxcar);
1176 free_fresize(&fresgauss);
1177
1178 return 0;
1179
1180 }
1181
1182 /*===========================================*/
1183 /* Example function 16: Lorentz force as defined in Fisher, 2012 */
1184 //
1185 // This calculation is adapted from Xudong's code
1186 // at /proj/cgem/lorentz/apps/lorentz.c
1187
1188 int computeLorentz(float *bx, float *by, float *bz, float *fx, float *fy, float *fz, int *dims,
1189 float *totfx_ptr, float *totfy_ptr, float *totfz_ptr, float *totbsq_ptr,
1190 float *epsx_ptr, float *epsy_ptr, float *epsz_ptr, int *mask, int *bitmask,
1191 float cdelt1, double rsun_ref, double rsun_obs)
1192
1193 {
1194
1195 int nx = dims[0];
1196 int ny = dims[1];
1197 int nxny = nx*ny;
1198 int j = 0;
1199 int index;
1200 double totfx = 0, totfy = 0, totfz = 0;
1201 double bsq = 0, totbsq = 0;
1202 double epsx = 0, epsy = 0, epsz = 0;
1203 double area = cdelt1*cdelt1*(rsun_ref/rsun_obs)*(rsun_ref/rsun_obs)*100.0*100.0;
1204 double k_h = -1.0 * area / (4. * PI) / 1.0e20;
1205 double k_z = area / (8. * PI) / 1.0e20;
1206
1207 if (nx <= 0 || ny <= 0) return 1;
1208
1209 for (int i = 0; i < nxny; i++)
1210 {
1211 if ( mask[i] < 70 || bitmask[i] < 30 ) continue;
1212 if isnan(bx[i]) continue;
1213 if isnan(by[i]) continue;
1214 if isnan(bz[i]) continue;
1215 fx[i] = bx[i] * bz[i] * k_h;
1216 fy[i] = by[i] * bz[i] * k_h;
1217 fz[i] = (bx[i] * bx[i] + by[i] * by[i] - bz[i] * bz[i]) * k_z;
1218 bsq = bx[i] * bx[i] + by[i] * by[i] + bz[i] * bz[i];
1219 totfx += fx[i]; totfy += fy[i]; totfz += fz[i];
1220 totbsq += bsq;
1221 }
1222
1223 *totfx_ptr = totfx;
1224 *totfy_ptr = totfy;
1225 *totfz_ptr = totfz;
1226 *totbsq_ptr = totbsq;
1227 *epsx_ptr = (totfx / k_h) / totbsq;
1228 *epsy_ptr = (totfy / k_h) / totbsq;
1229 *epsz_ptr = (totfz / k_z) / totbsq;
1230
1231 //printf("TOTBSQ=%f\n",*totbsq_ptr);
1232
1233 return 0;
1234
1235 }
1236
1237 /*==================KEIJI'S CODE =========================*/
1238
1239 // #include <omp.h>
1240 #include <math.h>
1241
1242 void greenpot(float *bx, float *by, float *bz, int nnx, int nny)
1243 {
1244 /* local workings */
1245 int inx, iny, i, j, n;
1246 /* local array */
1247 float *pfpot, *rdist;
1248 pfpot=(float *)malloc(sizeof(float) *nnx*nny);
1249 rdist=(float *)malloc(sizeof(float) *nnx*nny);
1250 float *bztmp;
1251 bztmp=(float *)malloc(sizeof(float) *nnx*nny);
1252 /* make nan */
1253 // unsigned long long llnan = 0x7ff0000000000000;
1254 // float NAN = (float)(llnan);
1255
1256 // #pragma omp parallel for private (inx)
1257 for (iny=0; iny < nny; iny++){for (inx=0; inx < nnx; inx++){pfpot[nnx*iny+inx] = 0.0;}}
1258 // #pragma omp parallel for private (inx)
1259 for (iny=0; iny < nny; iny++){for (inx=0; inx < nnx; inx++){rdist[nnx*iny+inx] = 0.0;}}
1260 // #pragma omp parallel for private (inx)
1261 for (iny=0; iny < nny; iny++){for (inx=0; inx < nnx; inx++){bx[nnx*iny+inx] = 0.0;}}
1262 // #pragma omp parallel for private (inx)
1263 for (iny=0; iny < nny; iny++){for (inx=0; inx < nnx; inx++){by[nnx*iny+inx] = 0.0;}}
1264 // #pragma omp parallel for private (inx)
1265 for (iny=0; iny < nny; iny++){for (inx=0; inx < nnx; inx++)
1266 {
1267 float val0 = bz[nnx*iny + inx];
1268 if (isnan(val0)){bztmp[nnx*iny + inx] = 0.0;}else{bztmp[nnx*iny + inx] = val0;}
1269 }}
1270
1271 // dz is the monopole depth
1272 float dz = 0.001;
1273
1274 // #pragma omp parallel for private (inx)
1275 for (iny=0; iny < nny; iny++){for (inx=0; inx < nnx; inx++)
1276 {
1277 float rdd, rdd1, rdd2;
1278 float r;
1279 rdd1 = (float)(inx);
1280 rdd2 = (float)(iny);
1281 rdd = rdd1 * rdd1 + rdd2 * rdd2 + dz * dz;
1282 rdist[nnx*iny+inx] = 1.0/sqrt(rdd);
1283 }}
1284
1285 int iwindow;
1286 if (nnx > nny) {iwindow = nnx;} else {iwindow = nny;}
1287 float rwindow;
1288 rwindow = (float)(iwindow);
1289 rwindow = rwindow * rwindow + 0.01; // must be of square
1290
1291 rwindow = 1.0e2; // limit the window size to be 10.
1292
1293 rwindow = sqrt(rwindow);
1294 iwindow = (int)(rwindow);
1295
1296 // #pragma omp parallel for private(inx)
1297 for (iny=0;iny<nny;iny++){for (inx=0;inx<nnx;inx++)
1298 {
1299 float val0 = bz[nnx*iny + inx];
1300 if (isnan(val0))
1301 {
1302 pfpot[nnx*iny + inx] = 0.0; // hmmm.. NAN;
1303 }
1304 else
1305 {
1306 float sum;
1307 sum = 0.0;
1308 int j2, i2;
1309 int j2s, j2e, i2s, i2e;
1310 j2s = iny - iwindow;
1311 j2e = iny + iwindow;
1312 if (j2s < 0){j2s = 0;}
1313 if (j2e > nny){j2e = nny;}
1314 i2s = inx - iwindow;
1315 i2e = inx + iwindow;
1316 if (i2s < 0){i2s = 0;}
1317 if (i2e > nnx){i2e = nnx;}
1318
1319 for (j2=j2s;j2<j2e;j2++){for (i2=i2s;i2<i2e;i2++)
1320 {
1321 float val1 = bztmp[nnx*j2 + i2];
1322 float rr, r1, r2;
1323 // r1 = (float)(i2 - inx);
1324 // r2 = (float)(j2 - iny);
1325 // rr = r1*r1 + r2*r2;
1326 // if (rr < rwindow)
1327 // {
1328 int di, dj;
1329 di = abs(i2 - inx);
1330 dj = abs(j2 - iny);
1331 sum = sum + val1 * rdist[nnx * dj + di] * dz;
1332 // }
1333 } }
1334 pfpot[nnx*iny + inx] = sum; // Note that this is a simplified definition.
1335 }
1336 } } // end of OpenMP parallelism
1337
1338 // #pragma omp parallel for private(inx)
1339 for (iny=1; iny < nny - 1; iny++){for (inx=1; inx < nnx - 1; inx++)
1340 {
1341 bx[nnx*iny + inx] = -(pfpot[nnx*iny + (inx+1)]-pfpot[nnx*iny + (inx-1)]) * 0.5;
1342 by[nnx*iny + inx] = -(pfpot[nnx*(iny+1) + inx]-pfpot[nnx*(iny-1) + inx]) * 0.5;
1343 } } // end of OpenMP parallelism
1344
1345 free(rdist);
1346 free(pfpot);
1347 free(bztmp);
1348 } // end of void func. greenpot
1349
1350
1351 /*===========END OF KEIJI'S CODE =========================*/
1352
1353 char *sw_functions_version() // Returns CVS version of sw_functions.c
1354 {
1355 return strdup("$Id");
1356 }
1357
1358 /* ---------------- end of this file ----------------*/