RTModel 2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4986 @@
1
+ // VBBinaryLensing v3.7 (2024)
2
+ //
3
+ // This code has been developed by Valerio Bozza (University of Salerno) and collaborators.
4
+ // Any use of this code for scientific publications should be acknowledged by a citation to:
5
+ // V. Bozza, E. Bachelet, F. Bartolic, T.M. Heintz, A.R. Hoag, M. Hundertmark, MNRAS 479 (2018) 5157
6
+ // If you use astrometry, user-defined limb darkening or Keplerian orbital motion, please cite
7
+ // V. Bozza, E. Khalouei and E. Bachelet (arXiv:2011.04780)
8
+ // The original methods present in v1.0 are described in
9
+ // V. Bozza, MNRAS 408 (2010) 2188
10
+ // Check the repository at http://www.fisica.unisa.it/GravitationAstrophysics/VBBinaryLensing.htm
11
+ // for the newest version.
12
+ //
13
+ // The code relies on the root solving algorithm by Jan Skworon and Andy Gould
14
+ // described in Skowron & Gould arXiv:1203.1034.
15
+ // Please also cite this paper if specifically relevant in your scientific publication.
16
+ // The original Fortran code available on http://www.astrouw.edu.pl/~jskowron/cmplx_roots_sg/
17
+ // has been translated to C++ by Tyler M. Heintz and Ava R. Hoag (2017)
18
+ //
19
+ // GNU Lesser General Public License applies to all parts of this code.
20
+ // Please read the separate LICENSE.txt file for more details.
21
+ //#define _PRINT_ERRORS2
22
+ //#define _ERRORS_ANALYTIC
23
+
24
+ #define _CRT_SECURE_NO_WARNINGS
25
+
26
+ #ifdef _WIN32
27
+ char systemslash = '\\';
28
+ #else
29
+ char systemslash = '/';
30
+ #endif
31
+
32
+ #include "VBBinaryLensingLibrary.h"
33
+ #define _USE_MATH_DEFINES
34
+ #include <math.h>
35
+ #include <stdio.h>
36
+ #include <stdlib.h>
37
+ #include <string.h>
38
+
39
+ #ifndef __unmanaged
40
+ using namespace VBBinaryLensingLibrary;
41
+ #endif
42
+ //////////////////////////////
43
+ //////////////////////////////
44
+ ////////Constructor and destructor
45
+ //////////////////////////////
46
+ //////////////////////////////
47
+
48
+ VBBinaryLensing::VBBinaryLensing() {
49
+ Obj[0] = -0.0397317;
50
+ Obj[1] = 0.998164;
51
+ Obj[2] = -0.045714;
52
+ // reference is ecliptic with x-axis toward the equinox.
53
+ // axial tilt at J2000 is 23:26:21.406 from JPL fundamental ephemeris
54
+ Eq2000[0] = 1;
55
+ Eq2000[1] = Eq2000[2] = Quad2000[0] = North2000[0] = 0;
56
+ Quad2000[1] = 0.9174820003578725;
57
+ Quad2000[2] = -0.3977772982704228;
58
+ North2000[1] = 0.3977772982704228;
59
+ North2000[2] = 0.9174820003578725;
60
+ t0old = 0.;
61
+ Tol = 1.e-2;
62
+ RelTol = 0;
63
+ tsat = 0;
64
+ possat = 0;
65
+ nsat = 0;
66
+ ndatasat = 0;
67
+ satellite = 0;
68
+ parallaxsystem = 0;
69
+ t0_par_fixed = -1;
70
+ t0_par = 7000;
71
+ minannuli = 1;
72
+ curLDprofile = LDlinear;
73
+ a1 = 0;
74
+ npLD = 0;
75
+ LDtab = rCLDtab = CLDtab=0;
76
+ Mag0 = 0;
77
+ NPcrit = 200;
78
+ ESPLoff = true;
79
+ multidark = false;
80
+ astrometry=false;
81
+ mass_luminosity_exponent = 4.0;
82
+ mass_radius_exponent = 0.9;
83
+ }
84
+
85
+ VBBinaryLensing::~VBBinaryLensing() {
86
+ if (nsat) {
87
+ for (int i = 0; i<nsat; i++) {
88
+ for (int j = 0; j<ndatasat[i]; j++) free(possat[i][j]);
89
+ free(tsat[i]);
90
+ free(possat[i]);
91
+ }
92
+ free(tsat);
93
+ free(possat);
94
+ free(ndatasat);
95
+ }
96
+ if (npLD > 0) {
97
+ free(LDtab);
98
+ free(rCLDtab);
99
+ }
100
+ }
101
+
102
+
103
+ //////////////////////////////
104
+ //////////////////////////////
105
+ ////////Critical curves and caustics
106
+ //////////////////////////////
107
+ //////////////////////////////
108
+
109
+
110
+ _sols *VBBinaryLensing::PlotCrit(double a1, double q1) {
111
+ complex a, q, ej, zr[4], x1, x2;
112
+ _sols *CriticalCurves;
113
+ _curve *Prov, *Prov2, *isso;
114
+ _point *pisso;
115
+ double SD, MD, CD, centeroffset;
116
+
117
+ a = complex(a1, 0.0);
118
+ q = complex(q1, 0.0);
119
+ centeroffset = a1 / 2.0*(1.0 - q1) / (1.0 + q1);
120
+
121
+ CriticalCurves = new _sols;
122
+ for (int i = 0; i<4; i++) {
123
+ Prov = new _curve;
124
+ CriticalCurves->append(Prov);
125
+ }
126
+
127
+ for (int j = 0; j<NPcrit; j++) {
128
+ ej = complex(cos(2 * j*M_PI / NPcrit), -sin(2 * j*M_PI / NPcrit));
129
+ complex coefs[5] = { a*a / 16.0*(4.0 - a*a*ej)*(1.0 + q),a*(q - 1.0),(q + 1.0)*(1.0 + a*a*ej / 2.0),0.0,-(1.0 + q)*ej };
130
+ cmplx_roots_gen(zr, coefs, 4, true, true);
131
+ if (j > 0) {
132
+ Prov2 = new _curve();
133
+ for (int i = 0; i < 4; i++) {
134
+ Prov2->append(zr[i].re + centeroffset, zr[i].im);
135
+ }
136
+ for (Prov = CriticalCurves->first; Prov; Prov = Prov->next) {
137
+ Prov2->closest(Prov->last, &pisso);
138
+ Prov2->drop(pisso);
139
+ Prov->append(pisso);
140
+ }
141
+ }
142
+ else {
143
+ Prov = CriticalCurves->first;
144
+ for (int i = 0; i < 4; i++) {
145
+ Prov->append(zr[i].re + centeroffset, zr[i].im);
146
+ Prov = Prov->next;
147
+ }
148
+ }
149
+ }
150
+
151
+ Prov = CriticalCurves->first;
152
+ while (Prov->next) {
153
+ SD = *(Prov->first) - *(Prov->last);
154
+ MD = 1.e100;
155
+ isso = 0;
156
+ for (Prov2 = Prov->next; Prov2; Prov2 = Prov2->next) {
157
+ CD = *(Prov2->first) - *(Prov->last);
158
+ if (CD<MD) {
159
+ MD = CD;
160
+ isso = Prov2;
161
+ }
162
+ }
163
+ if (MD<SD) {
164
+ CriticalCurves->drop(isso);
165
+ Prov->join(isso);
166
+ }
167
+ else {
168
+ Prov = Prov->next;
169
+ }
170
+ }
171
+
172
+ // Caustics
173
+
174
+ for (Prov = CriticalCurves->last; Prov; Prov = Prov->prev) {
175
+ Prov2 = new _curve;
176
+ for (_point *scanpoint = Prov->first; scanpoint; scanpoint = scanpoint->next) {
177
+ x1 = complex(scanpoint->x1 - centeroffset, 0.0);
178
+ x2 = complex(scanpoint->x2, 0.0);
179
+ Prov2->append(real(_L1) + centeroffset, real(_L2));
180
+ }
181
+ CriticalCurves->append(Prov2);
182
+ }
183
+ return CriticalCurves;
184
+ }
185
+
186
+ void VBBinaryLensing::PrintCau(double a, double q, double y1, double y2, double rho) {
187
+ _sols *CriticalCurves;
188
+ _curve *scancurve;
189
+ _point *scanpoint;
190
+ FILE *f;
191
+ int ncc;
192
+
193
+ CriticalCurves = PlotCrit(a, q);
194
+ f = fopen("outcurves.causticdata", "w");
195
+ fprintf(f, "%.16lf %.16lf %.16lf\n", y1,y2,rho);
196
+ ncc = CriticalCurves->length / 2;
197
+ scancurve = CriticalCurves->first;
198
+ for (int i = 0; i<2*ncc; i++) {
199
+ // scancurve = scancurve->next;
200
+ //}
201
+
202
+ //for (int i = 0; i<ncc; i++) {
203
+ fprintf(f, "Curve: %d\n", i + 1);
204
+ for (scanpoint = scancurve->first; scanpoint; scanpoint = scanpoint->next) {
205
+ fprintf(f, "%.16lf %.16lf\n", scanpoint->x1, scanpoint->x2);
206
+ }
207
+ scancurve = scancurve->next;
208
+ }
209
+ fclose(f);
210
+ delete CriticalCurves;
211
+ }
212
+
213
+
214
+ //////////////////////////////
215
+ //////////////////////////////
216
+ ////////Parallax settings and computation
217
+ //////////////////////////////
218
+ //////////////////////////////
219
+
220
+ void VBBinaryLensing::SetObjectCoordinates(char* modelfile, char* sateltabledir) {
221
+ double RA, Dec, dis, phiprec;
222
+ FILE* f;
223
+ char CoordinateString[512];
224
+ char filename[256];
225
+ int ic;
226
+
227
+ f = fopen(modelfile, "r");
228
+ if (f != 0) {
229
+ fscanf(f, "%[^\n]s", CoordinateString);
230
+ fclose(f);
231
+ SetObjectCoordinates(CoordinateString);
232
+
233
+ // Looking for satellite table files in the specified directory
234
+ sprintf(filename, "%s%csatellite*.txt", sateltabledir, systemslash);
235
+ nsat = 0;
236
+ for (unsigned char c = 32; c < 255; c++) {
237
+ filename[strlen(filename) - 5] = c;
238
+ f = fopen(filename, "r");
239
+ if (f != 0) {
240
+ nsat++;
241
+ fclose(f);
242
+ }
243
+ }
244
+
245
+
246
+ tsat = (double**)malloc(sizeof(double*) * nsat);
247
+ possat = (double***)malloc(sizeof(double**) * nsat);
248
+ ndatasat = (int*)malloc(sizeof(int) * nsat);
249
+
250
+ // Reading satellite table files
251
+ ic = 0;
252
+ for (unsigned char c = 32; c < 255; c++) {
253
+ filename[strlen(filename) - 5] = c;
254
+ f = fopen(filename, "r");
255
+ if (f != 0) {
256
+ int flag2 = 0;
257
+ long startpos = 0;
258
+ char teststring[1000];
259
+ ndatasat[ic] = 1;
260
+
261
+ // Finding start of data
262
+ while (!feof(f)) {
263
+ fscanf(f, "%s", teststring);
264
+ if (!feof(f)) {
265
+ fseek(f, 1, SEEK_CUR);
266
+ teststring[5] = 0;
267
+ if (strcmp(teststring, "$$SOE") == 0) {
268
+ flag2 = 1;
269
+ break;
270
+ }
271
+ }
272
+ }
273
+ // Finding end of data
274
+ if (flag2) {
275
+ flag2 = 0;
276
+ startpos = ftell(f);
277
+ while (!feof(f)) {
278
+ fscanf(f, "%[^\n]s", teststring);
279
+ if (!feof(f)) {
280
+ fseek(f, 1, SEEK_CUR);
281
+ teststring[5] = 0;
282
+ if (strcmp(teststring, "$$EOE") == 0) {
283
+ flag2 = 1;
284
+ break;
285
+ }
286
+ else {
287
+ ndatasat[ic]++;
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ // Allocating memory according to the length of the table
294
+ tsat[ic] = (double*)malloc(sizeof(double) * ndatasat[ic]);
295
+ possat[ic] = (double**)malloc(sizeof(double*) * ndatasat[ic]);
296
+ for (int j = 0; j < ndatasat[ic]; j++) {
297
+ possat[ic][j] = (double*)malloc(sizeof(double) * 3);
298
+ }
299
+ ndatasat[ic]--;
300
+
301
+ // Reading data
302
+ if (f) {
303
+ fseek(f, startpos, SEEK_SET);
304
+ for (int id = 0; id < ndatasat[ic]; id++) {
305
+
306
+ if (fscanf(f, "%lf %lf %lf %lf %lf", &(tsat[ic][id]), &RA, &Dec, &dis, &phiprec) == 5) {
307
+ tsat[ic][id] -= 2450000;
308
+ RA *= M_PI / 180;
309
+ Dec *= M_PI / 180;
310
+ for (int i = 0; i < 3; i++) {
311
+ possat[ic][id][i] = dis * (cos(RA) * cos(Dec) * Eq2000[i] + sin(RA) * cos(Dec) * Quad2000[i] + sin(Dec) * North2000[i]);
312
+ }
313
+ }
314
+ else {
315
+ ndatasat[ic] = id;
316
+ break;
317
+ }
318
+ }
319
+ fclose(f);
320
+ }
321
+
322
+ ic++;
323
+ }
324
+ }
325
+ }
326
+ else {
327
+ printf("\nFile not found!\n");
328
+ }
329
+ }
330
+
331
+ void VBBinaryLensing::SetObjectCoordinates(char *CoordinateString) {
332
+ double RA, Dec, hr, mn, sc, deg, pr, ssc;
333
+
334
+ if (nsat) {
335
+ for (int i = 0; i<nsat; i++) {
336
+ for (int j = 0; j<ndatasat[i]; j++) free(possat[i][j]);
337
+ free(tsat[i]);
338
+ free(possat[i]);
339
+ }
340
+ free(tsat);
341
+ free(possat);
342
+ free(ndatasat);
343
+ }
344
+ sscanf(CoordinateString, "%lf:%lf:%lf %lf:%lf:%lf", &hr, &mn, &sc, &deg, &pr, &ssc);
345
+ RA = (hr + mn / 60 + sc / 3600) * M_PI / 12,
346
+ Dec = (fabs(deg) + pr / 60 + ssc / 3600) * M_PI / 180;
347
+ if (deg < 0) Dec = -Dec;
348
+
349
+ for (int i = 0; i < 3; i++) {
350
+ Obj[i] = (cos(RA) * cos(Dec) * Eq2000[i] + sin(RA) * cos(Dec) * Quad2000[i] + sin(Dec) * North2000[i]);
351
+ rad[i] = Eq2000[i];
352
+ tang[i] = North2000[i];
353
+ }
354
+
355
+ if (t0_par_fixed == -1) t0_par_fixed = 0;
356
+
357
+ }
358
+
359
+ void VBBinaryLensing::ComputeParallax(double t, double t0, double *Et) {
360
+ static double a0 = 1.00000261, adot = 0.00000562; // Ephemeris from JPL website
361
+ static double e0 = 0.01671123, edot = -0.00004392;
362
+ static double inc0 = -0.00001531, incdot = -0.01294668;
363
+ static double L0 = 100.46457166, Ldot = 35999.37244981;
364
+ static double om0 = 102.93768193, omdot = 0.32327364;
365
+ static double deg = M_PI / 180;
366
+ static double a, e, inc, L, om, M, EE, dE, dM;
367
+ static double x1, y1, vx, vy, Ear[3], vEar[3];
368
+ static double Et0[2], vt0[2], r, sp, ty, Spit;
369
+ int c = 0, ic;
370
+
371
+ if (t0_par_fixed == 0) t0_par = t0;
372
+ if (t0_par_fixed == -1) {
373
+ printf("\nUse SetObjectCoordinates to input target coordinates");
374
+ }
375
+ else {
376
+
377
+ if (t0_par != t0old) {
378
+ t0old = t0_par;
379
+ ty = (t0_par - 1545) / 36525.0;
380
+
381
+ a = a0 + adot*ty;
382
+ e = e0 + edot*ty;
383
+ inc = (inc0 + incdot*ty)*deg;
384
+ L = (L0 + Ldot*ty)*deg;
385
+ om = (om0 + omdot*ty)*deg;
386
+
387
+ M = L - om;
388
+ M -= floor((M + M_PI) / (2 * M_PI)) * 2 * M_PI;
389
+
390
+ EE = M + e*sin(M);
391
+ dE = 1;
392
+ while (fabs(dE) > 1.e-8) {
393
+ dM = M - (EE - e*sin(EE));
394
+ dE = dM / (1 - e*cos(EE));
395
+ EE += dE;
396
+ }
397
+ x1 = a*(cos(EE) - e);
398
+ y1 = a*sqrt(1 - e*e)*sin(EE);
399
+ // r=a*(1-e*cos(EE));
400
+ vx = -a / (1 - e*cos(EE))*sin(EE)*Ldot*deg / 36525;
401
+ vy = a / (1 - e*cos(EE))*cos(EE)*sqrt(1 - e*e)*Ldot*deg / 36525;
402
+
403
+ Ear[0] = x1*cos(om) - y1*sin(om);
404
+ Ear[1] = x1*sin(om)*cos(inc) + y1*cos(om)*cos(inc);
405
+ Ear[2] = x1*sin(om)*sin(inc) + y1*cos(om)*sin(inc);
406
+ vEar[0] = vx*cos(om) - vy*sin(om);
407
+ vEar[1] = vx*sin(om)*cos(inc) + vy*cos(om)*cos(inc);
408
+ vEar[2] = vx*sin(om)*sin(inc) + vy*cos(om)*sin(inc);
409
+
410
+ sp = 0;
411
+ switch (parallaxsystem) {
412
+ case 1:
413
+ for (int i = 0; i < 3; i++) sp += North2000[i] * Obj[i];
414
+ for (int i = 0; i < 3; i++) rad[i] = -North2000[i] + sp*Obj[i];
415
+ break;
416
+ default:
417
+ for (int i = 0; i < 3; i++) sp += Ear[i] * Obj[i];
418
+ for (int i = 0; i < 3; i++) rad[i] = Ear[i] - sp*Obj[i];
419
+ break;
420
+ }
421
+
422
+ r = sqrt(rad[0] * rad[0] + rad[1] * rad[1] + rad[2] * rad[2]);
423
+ rad[0] /= r;
424
+ rad[1] /= r;
425
+ rad[2] /= r;
426
+ tang[0] = rad[1] * Obj[2] - rad[2] * Obj[1];
427
+ tang[1] = rad[2] * Obj[0] - rad[0] * Obj[2];
428
+ tang[2] = rad[0] * Obj[1] - rad[1] * Obj[0];
429
+
430
+ Et0[0] = Et0[1] = vt0[0] = vt0[1] = 0;
431
+ for (int i = 0; i < 3; i++) {
432
+ Et0[0] += Ear[i] * rad[i];
433
+ Et0[1] += Ear[i] * tang[i];
434
+ vt0[0] += vEar[i] * rad[i];
435
+ vt0[1] += vEar[i] * tang[i];
436
+ }
437
+ }
438
+
439
+ ty = (t - 1545) / 36525.0;
440
+
441
+ a = a0 + adot*ty;
442
+ e = e0 + edot*ty;
443
+ inc = (inc0 + incdot*ty)*deg;
444
+ L = (L0 + Ldot*ty)*deg;
445
+ om = (om0 + omdot*ty)*deg;
446
+
447
+ M = L - om;
448
+ M -= floor((M + M_PI) / (2 * M_PI)) * 2 * M_PI;
449
+
450
+ EE = M + e*sin(M);
451
+ dE = 1;
452
+ while (dE > 1.e-8) {
453
+ dM = M - (EE - e*sin(EE));
454
+ dE = dM / (1 - e*cos(EE));
455
+ EE += dE;
456
+ }
457
+ x1 = a*(cos(EE) - e);
458
+ y1 = a*sqrt(1 - e*e)*sin(EE);
459
+ // r=a*(1-e*cos(EE));
460
+
461
+ Ear[0] = x1*cos(om) - y1*sin(om);
462
+ Ear[1] = x1*sin(om)*cos(inc) + y1*cos(om)*cos(inc);
463
+ Ear[2] = x1*sin(om)*sin(inc) + y1*cos(om)*sin(inc);
464
+ Et[0] = Et[1] = 0;
465
+ for (int i = 0; i < 3; i++) {
466
+ Et[0] += Ear[i] * rad[i];
467
+ Et[1] += Ear[i] * tang[i];
468
+ }
469
+ Et[0] += -Et0[0] - vt0[0] * (t - t0_par);
470
+ Et[1] += -Et0[1] - vt0[1] * (t - t0_par);
471
+
472
+ if (satellite > 0 && satellite <= nsat) {
473
+ if (ndatasat[satellite - 1] > 2) {
474
+ int left, right;
475
+ if (t < tsat[satellite - 1][0]) {
476
+ ic = 0;
477
+ }
478
+ else {
479
+ if (t > tsat[satellite - 1][ndatasat[satellite - 1] - 1]) {
480
+ ic = ndatasat[satellite - 1] - 2;
481
+ }
482
+ else {
483
+ left = 0;
484
+ right = ndatasat[satellite - 1] - 1;
485
+ while (right - left > 1) {
486
+ ic = (right + left) / 2;
487
+ if (tsat[satellite - 1][ic] > t) {
488
+ right = ic;
489
+ }
490
+ else {
491
+ left = ic;
492
+ }
493
+ }
494
+ ic = left;
495
+ }
496
+ }
497
+ ty = t - tsat[satellite - 1][ic];
498
+ for (int i = 0; i < 3; i++) {
499
+ Spit = possat[satellite - 1][ic][i] * (1 - ty) + possat[satellite - 1][ic + 1][i] * ty;
500
+ Et[0] += Spit*rad[i];
501
+ Et[1] += Spit*tang[i];
502
+ }
503
+ }
504
+ }
505
+ }
506
+ }
507
+
508
+ //////////////////////////////
509
+ //////////////////////////////
510
+ ////////Basic magnification functions
511
+ //////////////////////////////
512
+ //////////////////////////////
513
+
514
+
515
+ double VBBinaryLensing::BinaryMag0(double a1, double q1, double y1v, double y2v, _sols **Images) {
516
+ static complex a, q, m1, m2, y;
517
+ static double av = -1.0, qv = -1.0;
518
+ static complex coefs[24], d1, d2, dy, dJ, dz;
519
+ static double Mag, Ai;
520
+
521
+ static _theta *stheta;
522
+ static _curve *Prov, *Prov2;
523
+ static _point *scan1, *scan2;
524
+
525
+ Mag = Ai = -1.0;
526
+ stheta = new _theta(-1.);
527
+ if ((a1 != av) || (q1 != qv)) {
528
+ av = a1;
529
+ qv = q1;
530
+ if (q1<1) {
531
+ a = complex(-a1, 0);
532
+ q = complex(q1, 0);
533
+ }
534
+ else {
535
+ a = complex(a1, 0);
536
+ q = complex(1 / q1, 0);
537
+ }
538
+ m1 = 1.0 / (1.0 + q);
539
+ m2 = q*m1;
540
+
541
+ coefs[20] = a;
542
+ coefs[21] = m1;
543
+ coefs[22] = m2;
544
+ coefs[6] = a*a;
545
+ coefs[7] = coefs[6] * a;
546
+ coefs[8] = m2*m2;
547
+ coefs[9] = coefs[6] * coefs[8];
548
+ coefs[10] = a*m2;
549
+ coefs[11] = a*m1;
550
+ coefs[23] = 0;
551
+
552
+ }
553
+ y = complex(y1v, y2v);
554
+ (*Images) = new _sols;
555
+ corrquad = corrquad2 = 0;
556
+ safedist = 10;
557
+ Prov = NewImages(y, coefs, stheta);
558
+ if (Prov->length == 0) {
559
+ delete Prov;
560
+ delete stheta;
561
+ return -1;
562
+ }
563
+ if (q.re < 0.01) {
564
+ safedist = y1v + coefs[11].re-1/a.re;
565
+ safedist *= safedist;
566
+ safedist += y2v*y2v - 36 * q1/(a1*a1);
567
+ }
568
+ Mag = 0.;
569
+ astrox1=0.;
570
+ astrox2=0.;
571
+ nim0 = 0;
572
+ for (scan1 = Prov->first; scan1; scan1 = scan2) {
573
+ scan2 = scan1->next;
574
+ Prov2 = new _curve(scan1);
575
+ //Prov2->append(scan1->x1, scan1->x2);
576
+ //Prov2->last->theta = stheta;
577
+ //Prov2->last->d = Prov2->first->d;
578
+ //Prov2->last->dJ = Prov2->first->dJ;
579
+ //Prov2->last->J2 = Prov2->first->J2;
580
+ //Prov2->last->ds = Prov2->first->ds;
581
+ (*Images)->append(Prov2);
582
+ Ai=fabs(1 / scan1->dJ);
583
+ Mag += Ai;
584
+ if(astrometry){
585
+ astrox1 +=scan1->x1*Ai;
586
+ astrox2 +=(scan1->x2)*Ai;
587
+ }
588
+ nim0++;
589
+ }
590
+ Prov->length = 0;
591
+ delete Prov;
592
+ delete stheta;
593
+ if(astrometry){
594
+ astrox1 /= (Mag);
595
+ astrox1 -=coefs[11].re;
596
+ astrox2 /= (Mag);
597
+ }
598
+ NPS = 1;
599
+ return Mag;
600
+
601
+ }
602
+
603
+ double VBBinaryLensing::BinaryMag0(double a1, double q1, double y1v, double y2v) {
604
+ static _sols *images;
605
+ static double mag;
606
+ mag = BinaryMag0(a1, q1, y1v, y2v, &images);
607
+ delete images;
608
+ return mag;
609
+ }
610
+
611
+ double VBBinaryLensing::BinaryMagSafe(double s, double q, double y1v, double y2v, double RS, _sols **images) {
612
+ static double Mag, mag1, mag2, RSi, RSo, delta1,delta2;
613
+ static int NPSsafe;
614
+ Mag = BinaryMag(s, q, y1v, y2v, RS,Tol,images);
615
+ RSi = RS;
616
+ RSo = RS;
617
+ NPSsafe = NPS;
618
+ if (Mag < 0) {
619
+ mag1 = -1;
620
+ delta1 = 3.33333333e-8;
621
+ while (mag1 < 0.1 && RSi>=0) {
622
+ delete *images;
623
+ delta1 *= 3.;
624
+ RSi = RS - delta1;
625
+ mag1 = (RSi > 0) ? BinaryMag(s, q, y1v, y2v, RSi, Tol, images) : BinaryMag0(s,q,y1v,y2v,images);
626
+ // printf("\n-safe1 %lf %lf %d", RSi, mag1, NPS);
627
+ NPSsafe += NPS;
628
+ }
629
+ if(mag1<0) mag1=1.0;
630
+ mag2 = -1;
631
+ delta2 = 3.33333333e-8;
632
+ while (mag2 < 0.1) {
633
+ delta2 *= 3.;
634
+ RSo = RS + delta2;
635
+ delete *images;
636
+ mag2 = BinaryMag(s, q, y1v, y2v, RSo, Tol, images);
637
+ // printf("\n-safe2 %lf %lf %d", RSo,mag2,NPS);
638
+ NPSsafe += NPS;
639
+ }
640
+ Mag = (mag1*delta2 + mag2*delta1)/(delta1+delta2);
641
+ }
642
+ NPS = NPSsafe;
643
+
644
+ return Mag;
645
+ }
646
+
647
+ double VBBinaryLensing::BinaryMag(double a1, double q1, double y1v, double y2v, double RSv, double Tol, _sols **Images) {
648
+ static complex a, q, m1, m2, y0, y, yc, z, zc;
649
+ static double av = -1.0, qv = -1.0;
650
+ static complex coefs[24], d1, d2, dy, dJ, dz;
651
+ static double thoff = 0.01020304,errbuff;
652
+ static double Mag, th;
653
+ ////////////////////////////
654
+ static double errimage, maxerr, currerr, Magold;
655
+ static int NPSmax, flag, NPSold,flagbad,flagbadmax=3;
656
+ static _curve *Prov, *Prov2;
657
+ static _point *scan1, *scan2;
658
+ static _thetas *Thetas;
659
+ static _theta *stheta, *itheta;
660
+
661
+ #ifdef _PRINT_TIMES
662
+ static double tim0, tim1;
663
+ #endif
664
+
665
+ // Initialization of the equation coefficients
666
+
667
+ if ((a1 != av) || (q1 != qv)) {
668
+ av = a1;
669
+ qv = q1;
670
+ if (q1<1) {
671
+ a = complex(-a1, 0);
672
+ q = complex(q1, 0);
673
+ }
674
+ else {
675
+ a = complex(a1, 0);
676
+ q = complex(1 / q1, 0);
677
+ }
678
+ m1 = 1.0 / (1.0 + q);
679
+ m2 = q*m1;
680
+
681
+ coefs[20] = a;
682
+ coefs[21] = m1;
683
+ coefs[22] = m2;
684
+ coefs[6] = a*a;
685
+ coefs[7] = coefs[6] * a;
686
+ coefs[8] = m2*m2;
687
+ coefs[9] = coefs[6] * coefs[8];
688
+ coefs[10] = a*m2;
689
+ coefs[11] = a*m1;
690
+
691
+ }
692
+ coefs[23] = RSv;
693
+
694
+ y0 = complex(y1v, y2v);
695
+ NPS = 1;
696
+ if (Tol>1.) {
697
+ errimage = 0.;
698
+ NPSmax = (int)(Tol);
699
+ }
700
+ else {
701
+ errimage = Tol*M_PI*RSv*RSv;
702
+ NPSmax =10000; // era 32000
703
+ }
704
+ errbuff = 0;
705
+
706
+ // Calculation of the images
707
+
708
+ (*Images) = new _sols;
709
+ Thetas = new _thetas;
710
+ th = thoff;
711
+ stheta = Thetas->insert(th);
712
+ stheta->maxerr = 1.e100;
713
+ y = y0 + complex(RSv*cos(thoff), RSv*sin(thoff));
714
+
715
+
716
+ #ifdef _PRINT_TIMES
717
+ tim0 = Environment::TickCount;
718
+ #endif
719
+ flag = 0;
720
+ flagbad = 0;
721
+ while (flag == 0) {
722
+ Prov = NewImages(y, coefs, stheta);
723
+ if (Prov->length > 0) {
724
+ flag = 1;
725
+ }
726
+ else {
727
+ delete Prov;
728
+ stheta->th += 0.01;
729
+ if (stheta->th > 2.0 * M_PI) {
730
+ delete Thetas;
731
+ return -1;
732
+ }
733
+ y = y0 + complex(RSv*cos(stheta->th), RSv*sin(stheta->th));
734
+ }
735
+ }
736
+ #ifdef _PRINT_TIMES
737
+ tim1 = Environment::TickCount;
738
+ GM += tim1 - tim0;
739
+ #endif
740
+ stheta = Thetas->insert(2.0*M_PI + Thetas->first->th);
741
+ stheta->maxerr = 0.;
742
+ stheta->Mag = 0.;
743
+ stheta->astrox1 = 0.;
744
+ stheta->astrox2 = 0.;
745
+ stheta->errworst = Thetas->first->errworst;
746
+ for (scan1 = Prov->first; scan1; scan1 = scan2) {
747
+ scan2 = scan1->next;
748
+ Prov2 = new _curve(scan1);
749
+ Prov2->append(scan1->x1, scan1->x2);
750
+ Prov2->last->theta = stheta;
751
+ Prov2->last->d = Prov2->first->d;
752
+ Prov2->last->dJ = Prov2->first->dJ;
753
+ Prov2->last->ds = Prov2->first->ds;
754
+ (*Images)->append(Prov2);
755
+ }
756
+ Prov->length = 0;
757
+ delete Prov;
758
+
759
+ th = M_PI + Thetas->first->th;
760
+ flag = 0;
761
+ Magold = -1.;
762
+ NPSold = 2;
763
+ currerr = 1.e100;
764
+ do {
765
+ stheta = Thetas->insert(th);
766
+ y = y0 + complex(RSv*cos(th), RSv*sin(th));
767
+ #ifdef _PRINT_TIMES
768
+ tim0 = Environment::TickCount;
769
+ #endif
770
+ //if (NPS == 422) {
771
+ // NPS = NPS;
772
+ //}
773
+
774
+ Prov = NewImages(y, coefs, stheta);
775
+ #ifdef _PRINT_TIMES
776
+ tim1 = Environment::TickCount;
777
+ GM += tim1 - tim0;
778
+ #endif
779
+ if (Prov->length > 0) {
780
+ flagbad = 0;
781
+ OrderImages((*Images), Prov);
782
+ if ((stheta->th - stheta->prev->th)*RSv < 1.e-11/* || stheta->maxerr > jumperrfactor * currerr || stheta->prev->maxerr > jumperrfactor * currerr*/) {
783
+ errbuff += stheta->maxerr + stheta->prev->maxerr;
784
+ stheta->maxerr = 0;
785
+ stheta->prev->maxerr = 0;
786
+ }
787
+ } else {
788
+ delete Prov;
789
+ flagbad++;
790
+ if (flagbad == flagbadmax) {
791
+ if (NPS < 16) {
792
+ delete Thetas;
793
+ return -1;
794
+ }
795
+ errbuff += stheta->prev->maxerr;
796
+ stheta->prev->maxerr = 0;
797
+ NPS--;
798
+ NPSmax--;
799
+ }
800
+ else {
801
+ th = (th - stheta->prev->th >= stheta->next->th - th) ? (th + flagbad * stheta->prev->th) / (1 + flagbad) : (th + flagbad * stheta->next->th) / (1 + flagbad);
802
+ }
803
+ Thetas->remove(stheta);
804
+ }
805
+
806
+ if (flagbad == 0 || flagbad == flagbadmax) {
807
+ maxerr = currerr = Mag = 0.;
808
+
809
+ astrox1 = astrox2 = 0.;
810
+ stheta = Thetas->first;
811
+
812
+ while (stheta->next) {
813
+ currerr += stheta->maxerr;
814
+ Mag += stheta->Mag;
815
+
816
+ if (astrometry) {
817
+ astrox1 += stheta->astrox1;
818
+ astrox2 += stheta->astrox2;
819
+ }
820
+ #ifndef _uniform
821
+ if (stheta->maxerr > maxerr) {
822
+ maxerr = stheta->maxerr;
823
+ #else
824
+ if (stheta->next->th * 0.99999 - stheta->th > maxerr) {
825
+ maxerr = stheta->next->th - stheta->th;
826
+ #endif
827
+ itheta = stheta;
828
+ }
829
+ stheta = stheta->next;
830
+ #ifdef _selectimage
831
+ if ((NPS == NPSmax - 1) && (fabs(floor(stheta->th / M_PI * _npoints / 2 + 0.5) - stheta->th / M_PI * _npoints / 2) < 1.e-8)) {
832
+ printf("%d %.15le\n", (int)floor(stheta->th / M_PI * _npoints / 2 + 0.5), Mag);
833
+ }
834
+ #endif
835
+ }
836
+ th = (itheta->th + itheta->next->th) / 2;
837
+ NPS++;
838
+ #ifndef _uniform
839
+ if (fabs(Magold - Mag) * 2 < errimage) {
840
+ flag++;
841
+ }
842
+ else {
843
+ flag = 0;
844
+ Magold = Mag;
845
+ NPSold = NPS + 8;
846
+ }
847
+ #else
848
+ currerr = 2 * errimage;
849
+ if (NPS == 2 * NPSold) {
850
+ if (fabs(Magold - Mag) * 2 < errimage) {
851
+ flag = NPSold;
852
+ }
853
+ else {
854
+ flag = 0;
855
+ NPSold = NPS;
856
+ Magold = Mag;
857
+ }
858
+ }
859
+ #endif
860
+ #ifdef _PRINT_ERRORS2
861
+ printf("\nNPS= %d Mag = %lf maxerr= %lg currerr =%lg th = %lf", NPS, Mag / (M_PI * RSv * RSv), maxerr / (M_PI * RSv * RSv), currerr / (M_PI * RSv * RSv), th);
862
+ #endif
863
+ }
864
+ } while ((currerr > errimage) && (currerr > RelTol * Mag) && (NPS < NPSmax) && ((flag < NPSold)/* || NPS<8 ||(currerr>10*errimage)*/)/*&&(flagits)*/);
865
+ if(astrometry){
866
+ astrox1 /= (Mag);
867
+ astrox2 /= (Mag);
868
+ }
869
+ Mag /= (M_PI*RSv*RSv);
870
+ therr = (currerr+errbuff) / (M_PI*RSv*RSv);
871
+
872
+ delete Thetas;
873
+ // if (NPS == NPSmax) return 1.e100*Tol; // Only for testing
874
+ return Mag;
875
+
876
+ }
877
+
878
+ double VBBinaryLensing::BinaryMag(double a1, double q1, double y1v, double y2v, double RSv, double Tol) {
879
+ static _sols *images;
880
+ static double mag;
881
+ mag = BinaryMag(a1, q1, y1v, y2v, RSv, Tol, &images);
882
+ delete images;
883
+ return mag;
884
+ }
885
+
886
+ double VBBinaryLensing::BinaryMag2(double s, double q, double y1v, double y2v, double rho) {
887
+ static double Mag, rho2, y2a;//, sms , dy1, dy2;
888
+ static int c;
889
+ static _sols *Images;
890
+
891
+ c = 0;
892
+
893
+ y2a = fabs(y2v);
894
+
895
+ Mag0 = BinaryMag0(s, q, y1v, y2a, &Images);
896
+ delete Images;
897
+ rho2 = rho*rho;
898
+ corrquad *= 6 * (rho2 + 1.e-4*Tol);
899
+ corrquad2 *= (rho+1.e-3);
900
+ if (corrquad<Tol && corrquad2<1 && (/*rho2 * s * s<q || */ safedist>4 * rho2)) {
901
+ Mag = Mag0;
902
+ }
903
+ else {
904
+ Mag = BinaryMagDark(s, q, y1v, y2a, rho, Tol);
905
+ }
906
+ Mag0 = 0;
907
+
908
+ if (y2v < 0) {
909
+ y_2 = y2v;
910
+ astrox2 = -astrox2;
911
+ }
912
+ return Mag;
913
+ }
914
+
915
+
916
+ double VBBinaryLensing::BinaryMagDark(double a, double q, double y1, double y2, double RSv, double Tolnew) {
917
+ static double Mag, Magold, Tolv;
918
+ static double LDastrox1,LDastrox2;
919
+ static double tc, lc, rc, cb,rb;
920
+ static int c, flag;
921
+ static double currerr, maxerr;
922
+ static annulus *first, *scan, *scan2;
923
+ static int nannold, totNPS;
924
+ static _sols *Images;
925
+
926
+ Mag = -1.0;
927
+ Magold = 0.;
928
+ Tolv = Tol;
929
+ LDastrox1 = LDastrox2 = 0.0;
930
+ c = 0;
931
+ totNPS = 1;
932
+
933
+ Tol = Tolnew;
934
+ y_1 = y1;
935
+ y_2 = y2;
936
+ while ((Mag<0.9) && (c<3)) {
937
+
938
+ first = new annulus;
939
+ first->bin = 0.;
940
+ first->cum = 0.;
941
+ if (Mag0 > 0.5) {
942
+ first->Mag = Mag0;
943
+ first->nim = nim0;
944
+ }
945
+ else {
946
+ first->Mag = BinaryMag0(a, q, y_1, y_2, &Images);
947
+ first->nim = Images->length;
948
+ delete Images;
949
+ }
950
+ if (astrometry) {
951
+ first->LDastrox1 = astrox1 * first->Mag;
952
+ first->LDastrox2 = astrox2 * first->Mag;
953
+ }
954
+ scr2 = sscr2 = 0;
955
+ first->f = LDprofile(0);
956
+ first->err = 0;
957
+ first->prev = 0;
958
+
959
+
960
+ first->next = new annulus;
961
+ scan = first->next;
962
+ scan->prev = first;
963
+ scan->next = 0;
964
+ scan->bin = 1.;
965
+ scan->cum = 1.;
966
+ scan->Mag = BinaryMagSafe(a, q, y_1, y_2, RSv, &Images);
967
+ if(astrometry){
968
+ scan->LDastrox1 = astrox1*scan->Mag;
969
+ scan->LDastrox2 = astrox2*scan->Mag;
970
+ }
971
+ totNPS += NPS;
972
+ scan->nim = Images->length;
973
+ delete Images;
974
+ scr2 = sscr2 = 1;
975
+ scan->f = LDprofile(0.9999999);
976
+ if (scan->nim == scan->prev->nim) {
977
+ scan->err = fabs((scan->Mag - scan->prev->Mag)*(scan->prev->f - scan->f) / 4);
978
+ }
979
+ else {
980
+ scan->err = fabs((scan->Mag)*(scan->prev->f - scan->f) / 4);
981
+ }
982
+
983
+ Magold = Mag = scan->Mag;
984
+ if(astrometry){
985
+ LDastrox1=scan->LDastrox1;
986
+ LDastrox2=scan->LDastrox2;
987
+ }
988
+ // scan->err+=scan->Mag*Tolv*0.25; //Impose calculation of intermediate annulus at mag>4. Why?
989
+ currerr = scan->err;
990
+ flag = 0;
991
+ nannuli = nannold = 1;
992
+ while (((flag<nannold + 5) && (currerr>Tolv) && (currerr>RelTol*Mag)) || (nannuli<minannuli)) {
993
+ maxerr = 0;
994
+ for (scan2 = first->next; scan2; scan2 = scan2->next) {
995
+ #ifdef _PRINT_ERRORS_DARK
996
+ printf("\n%d %lf %le | %lf %le", nannuli, scan2->Mag, scan2->err, Mag, currerr);
997
+ #endif
998
+ if (scan2->err>maxerr) {
999
+ maxerr = scan2->err;
1000
+ scan = scan2;
1001
+ }
1002
+ }
1003
+
1004
+ nannuli++;
1005
+ Magold = Mag;
1006
+ Mag -= (scan->Mag*scan->bin*scan->bin - scan->prev->Mag*scan->prev->bin*scan->prev->bin)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1007
+ if(astrometry){
1008
+ LDastrox1 -= (scan->LDastrox1*scan->bin*scan->bin - scan->prev->LDastrox1*scan->prev->bin*scan->prev->bin)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1009
+ LDastrox2 -= (scan->LDastrox2*scan->bin*scan->bin - scan->prev->LDastrox2*scan->prev->bin*scan->prev->bin)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1010
+ }
1011
+ currerr -= scan->err;
1012
+ lc = scan->prev->cum;
1013
+ rc = scan->cum;
1014
+ tc = (lc + rc) *0.5;
1015
+ cb = rCLDprofile(tc,scan->prev,scan);
1016
+ scan->prev->next = new annulus;
1017
+ scan->prev->next->prev = scan->prev;
1018
+ scan->prev = scan->prev->next;
1019
+ scan->prev->next = scan;
1020
+ scan->prev->bin = cb;
1021
+ scan->prev->cum = tc;
1022
+ scan->prev->f = LDprofile(cb);
1023
+ scan->prev->Mag = BinaryMagSafe(a, q, y_1, y_2, RSv*cb, &Images);
1024
+ if(astrometry){
1025
+ scan->prev->LDastrox1=astrox1*scan->prev->Mag;
1026
+ scan->prev->LDastrox2=astrox2*scan->prev->Mag;
1027
+ }
1028
+ totNPS += NPS;
1029
+ scan->prev->nim = Images->length;
1030
+ if (scan->prev->prev->nim == scan->prev->nim) {
1031
+ scan->prev->err = fabs((scan->prev->Mag - scan->prev->prev->Mag)*(scan->prev->prev->f - scan->prev->f)*(scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin) / 4);
1032
+ }
1033
+ else {
1034
+ scan->prev->err = fabs((scan->prev->bin*scan->prev->bin*scan->prev->Mag - scan->prev->prev->bin*scan->prev->prev->bin*scan->prev->prev->Mag)*(scan->prev->prev->f - scan->prev->f) / 4);
1035
+ }
1036
+ if (scan->nim == scan->prev->nim) {
1037
+ scan->err = fabs((scan->Mag - scan->prev->Mag)*(scan->prev->f - scan->f)*(scan->bin*scan->bin - scan->prev->bin*scan->prev->bin) / 4);
1038
+ }
1039
+ else {
1040
+ scan->err = fabs((scan->bin*scan->bin*scan->Mag - scan->prev->bin*scan->prev->bin*scan->prev->Mag)*(scan->prev->f - scan->f) / 4);
1041
+ }
1042
+ rb = (scan->Mag + scan->prev->prev->Mag - 2 * scan->prev->Mag);
1043
+ scan->prev->err += fabs(rb*(scan->prev->prev->f - scan->prev->f)*(scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin));
1044
+ scan->err += fabs(rb*(scan->prev->f - scan->f)*(scan->bin*scan->bin - scan->prev->bin*scan->prev->bin));
1045
+ #ifdef _PRINT_ERRORS_DARK
1046
+ printf("\n%d", Images->length);
1047
+ #endif
1048
+ delete Images;
1049
+
1050
+ Mag += (scan->bin*scan->bin*scan->Mag - cb*cb*scan->prev->Mag)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1051
+ Mag += (cb*cb*scan->prev->Mag - scan->prev->prev->bin*scan->prev->prev->bin*scan->prev->prev->Mag)*(scan->prev->cum - scan->prev->prev->cum) / (scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin);
1052
+ currerr += scan->err + scan->prev->err;
1053
+ if(astrometry){
1054
+ LDastrox1 += ( scan->bin*scan->bin*scan->LDastrox1 - cb*cb*scan->prev->LDastrox1)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1055
+ LDastrox1 += ( cb*cb*scan->prev->LDastrox1 - scan->prev->prev->bin*scan->prev->prev->bin*scan->prev->prev->LDastrox1)*(scan->prev->cum - scan->prev->prev->cum) / (scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin);
1056
+ LDastrox2 += ( scan->bin*scan->bin*scan->LDastrox2 - cb*cb*scan->prev->LDastrox2)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1057
+ LDastrox2 += ( cb*cb*scan->prev->LDastrox2 - scan->prev->prev->bin*scan->prev->prev->bin*scan->prev->prev->LDastrox2)*(scan->prev->cum - scan->prev->prev->cum) / (scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin);
1058
+ }
1059
+
1060
+
1061
+ if (fabs(Magold - Mag) * 2<Tolv) {
1062
+ flag++;
1063
+ }
1064
+ else {
1065
+ flag = 0;
1066
+ nannold = nannuli;
1067
+ }
1068
+
1069
+ }
1070
+
1071
+ if (multidark) {
1072
+ annlist = first;
1073
+ }else{
1074
+ while (first) {
1075
+ scan = first->next;
1076
+ delete first;
1077
+ first = scan;
1078
+ }
1079
+ }
1080
+
1081
+ Tolv /= 10;
1082
+ c++;
1083
+ }
1084
+ NPS = totNPS;
1085
+ therr = currerr;
1086
+ if(astrometry){
1087
+ LDastrox1/=Mag;
1088
+ LDastrox2/=Mag;
1089
+ astrox1=LDastrox1;
1090
+ astrox2=LDastrox2;
1091
+ }
1092
+ return Mag;
1093
+ }
1094
+
1095
+ void VBBinaryLensing::BinaryMagMultiDark(double a, double q, double y1, double y2, double RSv, double *a1_list, int nfil, double *mag_list, double Tol) {
1096
+ annulus *scan;
1097
+ int imax = 0;
1098
+ double Mag,r2,cr2,scr2,a1;
1099
+
1100
+ multidark = true;
1101
+
1102
+ for (int i = 1; i < nfil; i++) {
1103
+ if (a1_list[i] > a1_list[imax]) imax = i;
1104
+ }
1105
+ a1 = a1_list[imax];
1106
+ mag_list[imax] = BinaryMagDark(a, q, y1, y2, RSv, Tol);
1107
+
1108
+ for (int i = 0; i < nfil; i++) {
1109
+ if (i != imax) {
1110
+ Mag = 0;
1111
+ a1 = a1_list[i];
1112
+ for (scan = annlist->next; scan; scan = scan->next) {
1113
+ r2 = scan->bin*scan->bin;
1114
+ cr2 = 1 - r2;
1115
+ scr2 = sqrt(cr2);
1116
+ scan->cum = (3 * r2*(1 - a1) - 2 * a1*(scr2*cr2 - 1)) / (3 - a1);
1117
+ Mag += (scan->bin*scan->bin*scan->Mag - scan->prev->bin*scan->prev->bin*scan->prev->Mag)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1118
+ }
1119
+ mag_list[i] = Mag;
1120
+ }
1121
+ }
1122
+
1123
+ while (annlist) {
1124
+ scan = annlist->next;
1125
+ delete annlist;
1126
+ annlist = scan;
1127
+ }
1128
+
1129
+ multidark = false;
1130
+ }
1131
+
1132
+ double VBBinaryLensing::LDprofile(double r) {
1133
+ static int ir;
1134
+ static double rr,ret;
1135
+ switch(curLDprofile){
1136
+ case LDuser:
1137
+ rr = r * npLD;
1138
+ ir = (int)rr;
1139
+ rr -= ir;
1140
+ ret= LDtab[ir] * (1 - rr) + LDtab[ir + 1] * rr;
1141
+ break;
1142
+ case LDlinear:
1143
+ ret = 3 / (3 - a1)*(1 - a1 * scr2);
1144
+ break;
1145
+ case LDsquareroot:
1146
+ ret= 3 / (3 - a1 - 0.6*a2)*(1 - a1 * scr2 - a2 * sscr2);
1147
+ case LDquadratic:
1148
+ ret = 3 / (3 - a1 - 0.5*a2)*(1 - a1 * scr2 - a2 * sscr2);
1149
+ break;
1150
+ case LDlog:
1151
+ ret = 3 / (3 - a1 + 0.666666666666 * a2)*(1 - a1 * scr2 - a2 * sscr2);
1152
+ break;
1153
+ }
1154
+ return ret;
1155
+ }
1156
+
1157
+ double VBBinaryLensing::rCLDprofile(double tc,annulus *left,annulus *right) {
1158
+ static int ic;
1159
+ static double rc,cb,lc,r2,cr2,cc,lb,rb;
1160
+
1161
+ switch (curLDprofile) {
1162
+ case LDuser:
1163
+ rc = tc * npLD;
1164
+ ic = (int)rc;
1165
+ rc -= ic;
1166
+ cb = rCLDtab[ic] * (1 - rc) + rCLDtab[ic + 1] * rc;
1167
+ break;
1168
+ case LDlinear:
1169
+ lb = left->bin;
1170
+ rb = right->bin;
1171
+ lc = left->cum;
1172
+ rc = right->cum;
1173
+ do {
1174
+ cb = rb + (tc - rc)*(rb - lb) / (rc - lc);
1175
+ r2 = cb * cb;
1176
+ cr2 = 1 - r2;
1177
+ scr2 = 1-sqrt(cr2);
1178
+ cc = (3 * r2 - a1 * (r2 - 2 * scr2*cr2)) / (3 - a1);
1179
+ if (cc > tc) {
1180
+ rb = cb;
1181
+ rc = cc;
1182
+ }
1183
+ else {
1184
+ lb = cb;
1185
+ lc = cc;
1186
+ }
1187
+ } while (fabs(cc - tc) > 1.e-5);
1188
+ break;
1189
+ case LDsquareroot:
1190
+ lb = left->bin;
1191
+ rb = right->bin;
1192
+ lc = left->cum;
1193
+ rc = right->cum;
1194
+ do {
1195
+ cb = rb + (tc - rc)*(rb - lb) / (rc - lc);
1196
+ r2 = cb * cb;
1197
+ cr2 = 1 - r2;
1198
+ scr2 = sqrt(cr2);
1199
+ sscr2 = 1 - sqrt(scr2);
1200
+ scr2 = 1 - scr2;
1201
+ cc = (3 * r2 - a1 * (r2 - 2 * scr2*cr2) - 0.6*a2*(r2 - 4 * sscr2*cr2)) / (3 - a1 - 0.6*a2);
1202
+ if (cc > tc) {
1203
+ rb = cb;
1204
+ rc = cc;
1205
+ }
1206
+ else {
1207
+ lb = cb;
1208
+ lc = cc;
1209
+ }
1210
+ } while (fabs(cc - tc) > 1.e-5);
1211
+ break;
1212
+ case LDquadratic:
1213
+ lb = left->bin;
1214
+ rb = right->bin;
1215
+ lc = left->cum;
1216
+ rc = right->cum;
1217
+ do {
1218
+ cb = rb + (tc - rc)*(rb - lb) / (rc - lc);
1219
+ r2 = cb * cb;
1220
+ cr2 = 1 - r2;
1221
+ scr2 = 1- sqrt(cr2);
1222
+ sscr2 = scr2*scr2;
1223
+ cc = (3 * r2 - a1 * (r2 - 2 * scr2*cr2) + a2*(4*scr2-(2+4*scr2)*r2+1.5*r2*r2)) / (3 - a1 - 0.5*a2);
1224
+ if (cc > tc) {
1225
+ rb = cb;
1226
+ rc = cc;
1227
+ }
1228
+ else {
1229
+ lb = cb;
1230
+ lc = cc;
1231
+ }
1232
+ } while (fabs(cc - tc) > 1.e-5);
1233
+ break;
1234
+ case LDlog:
1235
+ lb = left->bin;
1236
+ rb = right->bin;
1237
+ lc = left->cum;
1238
+ rc = right->cum;
1239
+ do {
1240
+ cb = rb + (tc - rc)*(rb - lb) / (rc - lc);
1241
+ r2 = cb * cb;
1242
+ cr2 = 1 - r2;
1243
+ scr2 = sqrt(cr2);
1244
+ sscr2 = scr2*log(scr2);
1245
+ scr2 = 1 - scr2;
1246
+ cc = (3 * r2 - a1 * (r2 - 2 * scr2*cr2) + 2*a2*(scr2*(1+scr2*(scr2/3-1)) + sscr2*cr2)) / (3 - a1 + 0.6666666666666666*a2);
1247
+ if (cc > tc) {
1248
+ rb = cb;
1249
+ rc = cc;
1250
+ }
1251
+ else {
1252
+ lb = cb;
1253
+ lc = cc;
1254
+ }
1255
+ } while (fabs(cc - tc) > 1.e-5);
1256
+ break;
1257
+ }
1258
+
1259
+ return cb;
1260
+ }
1261
+
1262
+ void VBBinaryLensing::SetLDprofile(double (*UserLDprofile)(double),int newnpLD) {
1263
+ int ic,ir;
1264
+ if (npLD > 0) {
1265
+ free(LDtab);
1266
+ free(rCLDtab);
1267
+ }
1268
+ if (newnpLD > 0) {
1269
+ npLD = newnpLD;
1270
+ double npLD2 = npLD * npLD;
1271
+ LDtab = (double *)malloc(sizeof(double)*(npLD+1));
1272
+ CLDtab = (double *)malloc(sizeof(double)*(npLD + 1));
1273
+ rCLDtab = (double *)malloc(sizeof(double)*(npLD+1));
1274
+
1275
+ LDtab[0] = UserLDprofile(0.);
1276
+ CLDtab[0] = 0.;
1277
+ for (int i = 1; i <= npLD; i++) {
1278
+ LDtab[i] = UserLDprofile(((double) i)/ npLD);
1279
+ CLDtab[i] = CLDtab[i-1]+(LDtab[i]*i + LDtab[i - 1]*(i-1));
1280
+ }
1281
+ for (int i = 0; i <= npLD; i++) {
1282
+ LDtab[i] *= npLD2/CLDtab[npLD];
1283
+ CLDtab[i] /= CLDtab[npLD];
1284
+ }
1285
+ ic = 1;
1286
+ rCLDtab[0] = 0;
1287
+ ir = 1;
1288
+ while (ic < npLD) {
1289
+ while (CLDtab[ir] * npLD < ic && ir<npLD) ir++;
1290
+ rCLDtab[ic] = ((CLDtab[ir] - ((double) ic) / npLD)*(ir-1) + (((double)ic) / npLD - CLDtab[ir-1])*ir) / (CLDtab[ir] - CLDtab[ir - 1])/npLD;
1291
+ ic++;
1292
+ }
1293
+ rCLDtab[npLD] = 1;
1294
+
1295
+
1296
+ //printf("\n\n--------------------");
1297
+ //annulus left, right;
1298
+ //left.cum = left.bin=0;
1299
+ //right.cum = right.bin=1;
1300
+ //for (int i = 0; i <= npLD; i++) {
1301
+ // double rl, fl;
1302
+ // rl = ((double)i) / npLD;
1303
+ // scr2 = 1 - sqrt(1 - rl * rl);
1304
+ // fl = LDprofile(rl);
1305
+ // rl = rCLDprofile(((double) i) / npLD,&left,&right);
1306
+ // printf("\n%lf %lf %lf %lf", fl, LDtab[i], rl, rCLDtab[i]);
1307
+ //}
1308
+ //printf("\n--------------------\n\n");
1309
+
1310
+ free(CLDtab);
1311
+ curLDprofile = LDuser;
1312
+ }
1313
+ else {
1314
+ npLD = 0;
1315
+ curLDprofile = LDlinear;
1316
+ }
1317
+ }
1318
+
1319
+ void VBBinaryLensing::SetLDprofile(LDprofiles LDval) {
1320
+ if(npLD > 0) {
1321
+ npLD = 0;
1322
+ free(LDtab);
1323
+ free(rCLDtab);
1324
+ }
1325
+ curLDprofile = LDval;
1326
+ }
1327
+
1328
+ void VBBinaryLensing::LoadESPLTable(char *filename){
1329
+ FILE *f;
1330
+
1331
+ if((f = fopen(filename, "rb"))!=0){
1332
+ fread(ESPLin, sizeof(double), __rsize * __zsize, f);
1333
+ fread(ESPLout, sizeof(double), __rsize * __zsize, f);
1334
+ fread(ESPLinastro, sizeof(double), __rsize * __zsize, f);
1335
+ fread(ESPLoutastro, sizeof(double), __rsize * __zsize, f);
1336
+ fclose(f);
1337
+ ESPLoff=false;
1338
+ }else{
1339
+ printf("\nESPL table not found !");
1340
+ }
1341
+ }
1342
+
1343
+
1344
+ double VBBinaryLensing::PSPLMag(double u) {
1345
+ static double u2,u22;
1346
+ u2 = u * u;
1347
+ u22 = u2 + 2;
1348
+ if (astrometry) {
1349
+ astrox1 = u+u/u22;
1350
+ }
1351
+ return u22 / sqrt(u2 * (u2 + 4));
1352
+ }
1353
+
1354
+
1355
+ double VBBinaryLensing::ESPLMag(double u, double RSv) {
1356
+ double mag,z,fr,cz,cr,u2;
1357
+ int iz, ir;
1358
+
1359
+ if (ESPLoff) {
1360
+ printf("\nLoad ESPL table first!");
1361
+ return 0;
1362
+ }
1363
+
1364
+ fr = -10.857362047581296* log(0.01* RSv);
1365
+ if (fr > __rsize - 1) fr = __rsize -1.000001;
1366
+ if (fr < 0) printf("Source too large!");
1367
+ ir = (int) floor(fr);
1368
+ fr -= ir;
1369
+ cr = 1 - fr;
1370
+
1371
+ z = u / RSv;
1372
+
1373
+ if (z < 1) {
1374
+ z *= __zsize -1;
1375
+ iz = (int) floor(z);
1376
+ z -= iz;
1377
+ cz = 1 - z;
1378
+ mag = sqrt(1 + 4. / (RSv*RSv));
1379
+ mag *= ESPLin[ir][iz] * cr*cz + ESPLin[ir + 1][iz] * fr*cz + ESPLin[ir][iz + 1] * cr*z + ESPLin[ir + 1][iz + 1] * fr*z;
1380
+ if (astrometry) {
1381
+ astrox1=(1-1./(4+RSv*RSv))*u;
1382
+ astrox1 *= ESPLinastro[ir][iz] * cr*cz + ESPLinastro[ir + 1][iz] * fr*cz + ESPLinastro[ir][iz + 1] * cr*z + ESPLinastro[ir + 1][iz + 1] * fr*z;
1383
+ }
1384
+ }
1385
+ else {
1386
+ z = 0.99999999999999 / z;
1387
+ z *= __zsize - 1;
1388
+ iz = (int)floor(z);
1389
+ z -= iz;
1390
+ cz = 1 - z;
1391
+
1392
+ u2 = u*u;
1393
+ mag = (u2 + 2) / sqrt(u2*(u2 + 4));
1394
+ mag *= ESPLout[ir][iz] * cr*cz + ESPLout[ir + 1][iz] * fr*cz + ESPLout[ir][iz + 1] * cr*z + ESPLout[ir + 1][iz + 1] * fr*z;
1395
+ if (astrometry) {
1396
+ astrox1 = u * (u2 + 3) / (u2 + 2);
1397
+ astrox1 *= ESPLoutastro[ir][iz] * cr*cz + ESPLoutastro[ir + 1][iz] * fr*cz + ESPLoutastro[ir][iz + 1] * cr*z + ESPLoutastro[ir + 1][iz + 1] * fr*z;
1398
+ }
1399
+ }
1400
+
1401
+ return mag;
1402
+ }
1403
+
1404
+ double VBBinaryLensing::ESPLMag2(double u, double rho) {
1405
+ double Mag, u2,u6,rho2Tol;
1406
+ int c = 0;
1407
+
1408
+ //Tol1_4 = sqrt(2 / Tol);
1409
+ //u2 = u*u;
1410
+ //u3Tol = u2*u*Tol;
1411
+
1412
+ //if (u2 < Tol1_4) {
1413
+ // rho2 = rho*rho;
1414
+ // if (u3Tol > rho2*(1 + Tol1_4*rho)) {
1415
+
1416
+ u2 = u*u;
1417
+ rho2Tol = rho*rho/Tol;
1418
+ u6 = u2*u2*u2;
1419
+
1420
+ if (u6*(1+0.003*rho2Tol) > 0.027680640625*rho2Tol*rho2Tol) {
1421
+ Mag = (u2+2)/(u*sqrt(u2+4));
1422
+ if (astrometry) {
1423
+ astrox1 = u * (1 + 1 / (u2 + 2));
1424
+ }
1425
+ }
1426
+ else {
1427
+ Mag = ESPLMagDark(u, rho);
1428
+ }
1429
+ Mag0 = 0;
1430
+ return Mag;
1431
+ }
1432
+
1433
+ double VBBinaryLensing::ESPLMagDark(double u, double RSv) {
1434
+ double Mag = -1.0, Magold = 0., Tolv = Tol;
1435
+ double tc, rb, lc, rc, cb,u2;
1436
+ int c = 0, flag;
1437
+ double currerr, maxerr;
1438
+ annulus *first, *scan, *scan2;
1439
+ int nannold, totNPS = 1;
1440
+ double LDastrox1=0.0;
1441
+
1442
+ while ((Mag < 0.9) && (c < 3)) {
1443
+
1444
+ first = new annulus;
1445
+ first->bin = 0.;
1446
+ first->cum = 0.;
1447
+
1448
+ u2 = u * u;
1449
+ first->Mag = Mag0 = (u2 + 2) / (u*sqrt(u2 + 4));
1450
+ first->nim = 2;
1451
+ if (astrometry) {
1452
+ astrox1 = u * (u2 + 3) / (u2 + 2);
1453
+ first->LDastrox1 = astrox1 * first->Mag;
1454
+ }
1455
+
1456
+ scr2 = sscr2 = 0;
1457
+ first->f = LDprofile(0);
1458
+ first->err = 0;
1459
+ first->prev = 0;
1460
+
1461
+
1462
+ first->next = new annulus;
1463
+ scan = first->next;
1464
+ scan->prev = first;
1465
+ scan->next = 0;
1466
+ scan->bin = 1.;
1467
+ scan->cum = 1.;
1468
+ scan->Mag = ESPLMag(u, RSv);//ESPLMag(u, RSv, Tolv, &Images);
1469
+ if (astrometry) {
1470
+ scan->LDastrox1 = astrox1 * scan->Mag;
1471
+ }
1472
+ scan->nim = 2;
1473
+ scr2 = sscr2 = 1;
1474
+ scan->f = LDprofile(0.9999999);
1475
+ scan->err = fabs((scan->Mag - scan->prev->Mag)*(scan->prev->f - scan->f) / 4);
1476
+
1477
+ Magold = Mag = scan->Mag;
1478
+ if(astrometry){
1479
+ LDastrox1=scan->LDastrox1;
1480
+ }
1481
+ //
1482
+ // scan->err+=scan->Mag*Tolv*0.25; //Impose calculation of intermediate annulus at mag>4. Why?
1483
+ currerr = scan->err;
1484
+ flag = 0;
1485
+ nannuli = nannold = 1;
1486
+ while (((flag<nannold + 5) && (currerr>Tolv) && (currerr>RelTol*Mag)) || (nannuli<minannuli)) {
1487
+ maxerr = 0;
1488
+ for (scan2 = first->next; scan2; scan2 = scan2->next) {
1489
+ #ifdef _PRINT_ERRORS_DARK
1490
+ printf("\n%d %lf %le | %lf %le", nannuli, scan2->Mag, scan2->err, Mag, currerr);
1491
+ #endif
1492
+ if (scan2->err>maxerr) {
1493
+ maxerr = scan2->err;
1494
+ scan = scan2;
1495
+ }
1496
+ }
1497
+
1498
+ nannuli++;
1499
+ Magold = Mag;
1500
+ Mag -= (scan->Mag*scan->bin*scan->bin - scan->prev->Mag*scan->prev->bin*scan->prev->bin)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1501
+ if(astrometry){
1502
+ LDastrox1 -= (scan->LDastrox1*scan->bin*scan->bin - scan->prev->LDastrox1*scan->prev->bin*scan->prev->bin)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1503
+
1504
+ }
1505
+ currerr -= scan->err;
1506
+ rc = scan->cum;
1507
+ lc = scan->prev->cum;
1508
+ tc = (lc + rc) / 2;
1509
+ cb = rCLDprofile(tc, scan->prev, scan);
1510
+
1511
+ scan->prev->next = new annulus;
1512
+ scan->prev->next->prev = scan->prev;
1513
+ scan->prev = scan->prev->next;
1514
+ scan->prev->next = scan;
1515
+ scan->prev->bin = cb;
1516
+ scan->prev->cum = tc;
1517
+ scan->prev->f = LDprofile(cb);
1518
+ scan->prev->Mag = ESPLMag(u, RSv*cb);
1519
+ if(astrometry){
1520
+ scan->prev->LDastrox1=astrox1*scan->prev->Mag;
1521
+
1522
+ }
1523
+ scan->prev->nim = 2;
1524
+ scan->prev->err = fabs((scan->prev->Mag - scan->prev->prev->Mag)*(scan->prev->prev->f - scan->prev->f)*(scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin) / 4);
1525
+ scan->err = fabs((scan->Mag - scan->prev->Mag)*(scan->prev->f - scan->f)*(scan->bin*scan->bin - scan->prev->bin*scan->prev->bin) / 4);
1526
+ rb = (scan->Mag + scan->prev->prev->Mag - 2 * scan->prev->Mag);
1527
+ scan->prev->err += fabs(rb*(scan->prev->prev->f - scan->prev->f)*(scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin));
1528
+ scan->err += fabs(rb*(scan->prev->f - scan->f)*(scan->bin*scan->bin - scan->prev->bin*scan->prev->bin));
1529
+ #ifdef _PRINT_ERRORS_DARK
1530
+ printf("\n%d", Images->length);
1531
+ #endif
1532
+
1533
+ Mag += (scan->bin*scan->bin*scan->Mag - cb*cb*scan->prev->Mag)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1534
+ Mag += (cb*cb*scan->prev->Mag - scan->prev->prev->bin*scan->prev->prev->bin*scan->prev->prev->Mag)*(scan->prev->cum - scan->prev->prev->cum) / (scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin);
1535
+ if(astrometry){
1536
+ LDastrox1 += ( scan->bin*scan->bin*scan->LDastrox1 - cb*cb*scan->prev->LDastrox1)*(scan->cum - scan->prev->cum) / (scan->bin*scan->bin - scan->prev->bin*scan->prev->bin);
1537
+ LDastrox1 += ( cb*cb*scan->prev->LDastrox1 - scan->prev->prev->bin*scan->prev->prev->bin*scan->prev->prev->LDastrox1)*(scan->prev->cum - scan->prev->prev->cum) / (scan->prev->bin*scan->prev->bin - scan->prev->prev->bin*scan->prev->prev->bin);
1538
+
1539
+ }
1540
+ currerr += scan->err + scan->prev->err;
1541
+
1542
+ if (fabs(Magold - Mag) * 2<Tolv) {
1543
+ flag++;
1544
+ }
1545
+ else {
1546
+ flag = 0;
1547
+ nannold = nannuli;
1548
+ }
1549
+
1550
+ }
1551
+
1552
+ while (first) {
1553
+ scan = first->next;
1554
+ delete first;
1555
+ first = scan;
1556
+ }
1557
+
1558
+ Tolv /= 10;
1559
+ c++;
1560
+ }
1561
+ therr = currerr;
1562
+ if(astrometry){
1563
+ LDastrox1/=Mag;
1564
+ astrox1=LDastrox1;
1565
+
1566
+ }
1567
+ return Mag;
1568
+ }
1569
+
1570
+ //////////////////////////////
1571
+ //////////////////////////////
1572
+ ////////New (v2) light curve functions
1573
+ //////////////////////////////
1574
+ //////////////////////////////
1575
+
1576
+ void VBBinaryLensing::PSPLLightCurve(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1577
+ double u0=exp(pr[0]), t0=pr[2],tE_inv=exp(-pr[1]),tn,u;
1578
+
1579
+ for (int i = 0; i < np; i++) {
1580
+ tn = (ts[i] - t0) *tE_inv;
1581
+ u = tn*tn + u0*u0;
1582
+
1583
+ y1s[i] = -tn;
1584
+ y2s[i] = -u0;
1585
+ mags[i]= (u + 2) / sqrt(u*(u + 4));
1586
+
1587
+ }
1588
+ }
1589
+
1590
+
1591
+ void VBBinaryLensing::PSPLLightCurveParallax(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1592
+ double u0 = pr[0], t0 = pr[2], tE_inv = exp(-pr[1]), tn, u,u1,pai1=pr[3],pai2=pr[4];
1593
+ double Et[2];
1594
+ t0old = 0;
1595
+
1596
+ for (int i = 0; i < np; i++) {
1597
+ ComputeParallax(ts[i], t0, Et);
1598
+ tn = (ts[i] - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
1599
+ u1 = u0 + pai1*Et[1] - pai2*Et[0];
1600
+ u = tn*tn + u1*u1;
1601
+
1602
+ y1s[i] = -tn;
1603
+ y2s[i] = -u1;
1604
+ mags[i] = (u + 2) / sqrt(u*(u + 4));
1605
+ }
1606
+
1607
+ }
1608
+
1609
+
1610
+ void VBBinaryLensing::ESPLLightCurve(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1611
+ double u0 = exp(pr[0]), t0 = pr[2], tE_inv = exp(-pr[1]), tn, u,rho=exp(pr[3]);
1612
+
1613
+ for (int i = 0; i < np; i++) {
1614
+ tn = (ts[i] - t0) *tE_inv;
1615
+ u = sqrt(tn*tn + u0*u0);
1616
+
1617
+ y1s[i] = -tn;
1618
+ y2s[i] = -u0;
1619
+ mags[i] = ESPLMag2(u,rho);
1620
+
1621
+ }
1622
+ }
1623
+
1624
+ void VBBinaryLensing::ESPLLightCurveParallax(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1625
+ double u0 = pr[0], t0 = pr[2], tE_inv = exp(-pr[1]), tn, u, u1, rho = exp(pr[3]), pai1 = pr[4], pai2 = pr[5];
1626
+ double Et[2];
1627
+ t0old = 0;
1628
+
1629
+ for (int i = 0; i < np; i++) {
1630
+ ComputeParallax(ts[i], t0, Et);
1631
+ tn = (ts[i] - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
1632
+ u1 = u0 + pai1*Et[1] - pai2*Et[0];
1633
+ u = sqrt( tn*tn + u1*u1);
1634
+
1635
+ y1s[i] = -tn;
1636
+ y2s[i] = -u1;
1637
+ mags[i] = ESPLMag2(u, rho);
1638
+ }
1639
+
1640
+ }
1641
+
1642
+
1643
+ void VBBinaryLensing::BinaryLightCurve(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1644
+ double s = exp(pr[0]), q = exp(pr[1]), rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]);
1645
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
1646
+
1647
+ // _sols *Images; double Mag; // For debugging
1648
+
1649
+ for (int i = 0; i < np; i++) {
1650
+ tn = (ts[i] - pr[6]) * tE_inv;
1651
+ y1s[i] = pr[2] * salpha - tn*calpha;
1652
+ y2s[i] = -pr[2] * calpha - tn*salpha;
1653
+ mags[i] = BinaryMag2(s, q, y1s[i], y2s[i], rho);
1654
+
1655
+ //Mag=BinaryMag(s, q, y1s[i], y2s[i], rho, Tol,&Images); // For debugging
1656
+ //delete Images;
1657
+ //mags[i] -= Mag;
1658
+ //if (fabs(mags[i]) > Tol) {
1659
+ // printf("\n%lf %lf %lf", y1s[i], y2s[i], mags[i]);
1660
+ //}
1661
+ }
1662
+ }
1663
+
1664
+
1665
+ void VBBinaryLensing::BinaryLightCurveW(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1666
+ double s = exp(pr[0]), q = exp(pr[1]), rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]),t0,u0;
1667
+ double salpha = sin(pr[3]), calpha = cos(pr[3]),xc;
1668
+
1669
+ xc = (s - 1 / s) / (1 + q);
1670
+ if (xc<0) xc = 0.;
1671
+ t0 = pr[6] + xc*calpha/tE_inv;
1672
+ u0 = pr[2] + xc*salpha;
1673
+
1674
+ for (int i = 0; i < np; i++) {
1675
+ tn = (ts[i] - t0) * tE_inv;
1676
+ y1s[i] = u0 * salpha - tn*calpha;
1677
+ y2s[i] = -u0 * calpha - tn*salpha;
1678
+ mags[i] = BinaryMag2(s, q, y1s[i], y2s[i], rho);
1679
+ }
1680
+ }
1681
+
1682
+
1683
+ void VBBinaryLensing::BinaryLightCurveParallax(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1684
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], rho = exp(pr[4]), tn,u, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8];
1685
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
1686
+ double Et[2];
1687
+ t0old = 0;
1688
+
1689
+ for (int i = 0; i < np; i++) {
1690
+ ComputeParallax(ts[i], t0, Et);
1691
+ tn = (ts[i] - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
1692
+ u = u0 + pai1*Et[1] - pai2*Et[0];
1693
+ y1s[i] = u * salpha - tn*calpha;
1694
+ y2s[i] = -u * calpha - tn*salpha;
1695
+ mags[i] = BinaryMag2(s, q, y1s[i], y2s[i], rho);
1696
+ }
1697
+ }
1698
+
1699
+
1700
+ void VBBinaryLensing::BinaryLightCurveOrbital(double *pr, double *ts, double *mags, double *y1s, double *y2s, double *seps, int np) {
1701
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11];
1702
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
1703
+ double Et[2];
1704
+ double w, phi0, inc, phi, Cinc, Sinc, Cphi, Sphi, Cphi0, Sphi0, COm, SOm,s_true;
1705
+ double w13, w123, den, den0, u;
1706
+ t0old = 0;
1707
+
1708
+ w13 = w1*w1 + w3*w3;
1709
+ w123 = sqrt(w13 + w2*w2);
1710
+ w13 = sqrt(w13);
1711
+ if (w13>1.e-8) {
1712
+ w3 = (w3>1.e-8) ? w3 : 1.e-8;
1713
+ w = w3*w123 / w13;
1714
+ inc = acos(w2*w3 / w13 / w123);
1715
+ phi0 = atan2(-w1*w123, w3*w13);
1716
+ }
1717
+ else {
1718
+ w = w2;
1719
+ inc = 0.;
1720
+ phi0 = 0.;
1721
+ }
1722
+ Cphi0 = cos(phi0);
1723
+ Sphi0 = sin(phi0);
1724
+ Cinc = cos(inc);
1725
+ Sinc = sin(inc);
1726
+ den0 = sqrt(Cphi0*Cphi0 + Cinc*Cinc*Sphi0*Sphi0);
1727
+ s_true = s / den0; // orbital radius
1728
+ COm = (Cphi0*calpha + Cinc*salpha*Sphi0) / den0;
1729
+ SOm = (Cphi0*salpha - Cinc*calpha*Sphi0) / den0;
1730
+
1731
+ for (int i = 0; i < np; i++) {
1732
+ ComputeParallax(ts[i], t0, Et);
1733
+
1734
+ phi = (ts[i] - t0_par)*w + phi0;
1735
+ Cphi = cos(phi);
1736
+ Sphi = sin(phi);
1737
+ den = sqrt(Cphi*Cphi + Cinc*Cinc*Sphi*Sphi);
1738
+ seps[i] = s_true*den; // projected separation at time ts[i]
1739
+
1740
+ u = u0 + pai1*Et[1] - pai2*Et[0];
1741
+ tn = (ts[i] - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
1742
+ y1s[i] = (Cphi*(u*SOm - tn*COm) + Cinc*Sphi*(u*COm + tn*SOm)) / den;
1743
+ y2s[i] = (-Cphi*(u*COm + tn*SOm) - Cinc*Sphi*(tn*COm - u*SOm)) / den;
1744
+ mags[i] = BinaryMag2(seps[i], q, y1s[i], y2s[i], rho);
1745
+ }
1746
+ }
1747
+
1748
+
1749
+ void VBBinaryLensing::BinaryLightCurveKepler(double *pr, double *ts, double *mags, double *y1s, double *y2s, double *seps, int np) {
1750
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], alpha = pr[3], rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11], szs = pr[12], ar = pr[13]+1.e-8;
1751
+ double Et[2];
1752
+ double u, w22, w11, w33, w12, w23, szs2, ar2, EE, dE;
1753
+ double wt2, smix, sqsmix, e, h, snu, co1EE0, co2EE0,cosE,sinE, co1tperi, tperi, EE0, M, a, St, psi, dM, conu, n;
1754
+ double arm1, arm2;
1755
+ double X[3], Y[3], Z[3],r[2],x[2];
1756
+ t0old = 0;
1757
+
1758
+ smix = 1 + szs * szs;
1759
+ sqsmix = sqrt(smix);
1760
+ w22 = w2 * w2;
1761
+ w11 = w1 * w1;
1762
+ w33 = w3 * w3;
1763
+ w12 = w11 + w22;
1764
+ w23 = w22 + w33;
1765
+ wt2 = w12 + w33;
1766
+
1767
+ szs2 = szs * szs;
1768
+ ar2 = ar * ar;
1769
+ arm1 = ar - 1;
1770
+ arm2 = 2 * ar - 1;
1771
+ // n = sqrt(wt2) / (ar*sqrt(-1 + 2 * ar)*sqrt(smix));
1772
+ n = sqrt(wt2 / arm2 / smix) / ar;
1773
+ Z[0] = -szs * w2;
1774
+ Z[1] = szs * w1 - w3;
1775
+ Z[2] = w2;
1776
+ h = sqrt(Z[0] * Z[0] + Z[1] * Z[1] + Z[2] * Z[2]);
1777
+ for (int i = 0; i < 3; i++) Z[i] /= h;
1778
+ X[0] = -ar * w11 + arm1 * w22 - arm2 * szs*w1*w3 + arm1 * w33;
1779
+ X[1] = -arm2 *w2*(w1 + szs * w3);
1780
+ X[2] = arm1 * szs*w12 - arm2 * w1*w3 - ar * szs*w33;
1781
+ e = sqrt(X[0] * X[0] + X[1] * X[1] + X[2] * X[2]);
1782
+ for (int i = 0; i < 3; i++) X[i] /= e;
1783
+ e /= ar * sqsmix*wt2;
1784
+ Y[0] = Z[1] * X[2] - Z[2] * X[1];
1785
+ Y[1] = Z[2] * X[0] - Z[0] * X[2];
1786
+ Y[2] = Z[0] * X[1] - Z[1] * X[0];
1787
+
1788
+ // h = sqrt((smix)*w22 + (szs*w1 - w3)*(szs*w1 - w3));
1789
+ // co1e = (1 - ar)*(1 - ar) + ar2 * szs2 + (-1 + 2 * ar)*(w11*(1 - szs2) - szs2 * w22 + 2 * szs*w1*w3) / wt2;
1790
+ // co1nu = ar2 * szs2 + arm2 * (w11*(1 - szs2) - szs2 * w22 + 2 * szs*w1*w3) / wt2;
1791
+ // co1e = arm1*arm1 + co1nu;
1792
+ // coe2 = ar2 * smix;
1793
+ // e = sqrt(co1e/coe2);
1794
+ // co1nu = (-1 + 2 * ar)*sqrt(smix)*(w1 + szs * w3)*(szs2*(w12)-2 * szs*w1*w3 + w23);
1795
+ // co2nu = ar * e*h*(smix)*sqrt((smix))*wt2;
1796
+ conu = (X[0] + X[2] * szs) / sqsmix;
1797
+ co1EE0 = conu + e;
1798
+ co2EE0 = 1 + e * conu;
1799
+ cosE = co1EE0 / co2EE0;
1800
+ EE0 = acos(cosE);
1801
+ snu = (Y[0] + Y[2] * szs);
1802
+ EE0 *= (snu > 0) ? 1 : -1;
1803
+ sinE = sqrt(1 - cosE * cosE)*((snu > 0) ? 1 : -1);
1804
+ co1tperi = e * sinE;
1805
+ tperi = t0_par - (EE0 - co1tperi) / n;
1806
+ // coX = ar * e*sqrt(smix)*wt2;
1807
+ //coX1 = -ar * w11 + (-1 + ar)*w22 + (1 - 2 * ar)*szs*w1*w3 + (-1 + ar)*w33;
1808
+ //coX2 = (-1 + 2 * ar)*w1*w23 + szs2 * w1*((-1 + ar)*w12 - ar * w33) + szs * w3*((2 - 3 * ar)*w11 + ar * w23);
1809
+ //coY1 = -(-1 + 2 * ar)*w2*(w1 + szs * w3);
1810
+ //coY2 = w2 * (-szs2 * w12 + 2 * szs*w1*w3 - w23 + ar * (-4 * szs*w1*w3 + szs2 * (w12 - w33) + (-w11 + w23)));
1811
+ for (int i = 0; i < np; i++) {
1812
+ ComputeParallax(ts[i], t0, Et);
1813
+ M = n * (ts[i] - tperi);
1814
+ EE = M + e * sin(M);
1815
+ dE = 1;
1816
+ while (fabs(dE) > 1.e-8) {
1817
+ dM = M - (EE - e * sin(EE));
1818
+ dE = dM / (1 - e * cos(EE));
1819
+ EE += dE;
1820
+ }
1821
+
1822
+ a = ar * s*sqrt(smix);
1823
+
1824
+ r[0] = a * (cos(EE) - e);
1825
+ r[1] = a * sqrt(1 - e * e)*sin(EE);
1826
+ x[0] = r[0] * X[0] + r[1] * Y[0]; // (coX1*x[1] + coX2 * y[1] / h) / coX;
1827
+ x[1] = r[0] * X[1] + r[1] * Y[1]; //(coY1*x[1] + y[1] * coY2 / h) / coX;
1828
+ St = sqrt(x[0] * x[0] + x[1] * x[1]);
1829
+ psi = atan2(x[1], x[0]);// +((ar > 1) ? 0 : M_PI);
1830
+ u = u0 + pai1 * Et[1] - pai2 * Et[0];
1831
+ tn = (ts[i] - t0) * tE_inv + pai1 * Et[0] + pai2 * Et[1];
1832
+ y1s[i] = -tn * cos(alpha + psi) + u * sin(alpha + psi);
1833
+ y2s[i] = -u * cos(alpha + psi) - tn * sin(alpha + psi);
1834
+ seps[i] = St;
1835
+
1836
+ mags[i] = BinaryMag2(seps[i], q, y1s[i], y2s[i], rho);
1837
+
1838
+ }
1839
+ }
1840
+
1841
+ void VBBinaryLensing::BinSourceLightCurve(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1842
+ double u1 = pr[2], u2=pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR=exp(pr[1]), tn, u;
1843
+
1844
+ for (int i = 0; i < np; i++) {
1845
+ tn = (ts[i] - t01) * tE_inv;
1846
+ u = tn*tn + u1*u1;
1847
+
1848
+ y1s[i] = -tn;
1849
+ y2s[i] = -u1;
1850
+ mags[i] = (u + 2) / sqrt(u*(u + 4));
1851
+
1852
+ tn = (ts[i] - t02) * tE_inv;
1853
+ u = tn*tn + u2*u2;
1854
+
1855
+ mags[i] += FR*(u + 2) / sqrt(u*(u + 4));
1856
+ mags[i] /= (1 + FR);
1857
+
1858
+ }
1859
+
1860
+ }
1861
+
1862
+
1863
+ void VBBinaryLensing::BinSourceLightCurveParallax(double *pr, double *ts, double *mags, double *y1s, double *y2s, int np) {
1864
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), tn, u, u0, pai1 = pr[6], pai2 = pr[7], w1 = pr[8], w2 = pr[9], w3 = pr[10];
1865
+ double Et[2];
1866
+ t0old = 0;
1867
+
1868
+ for (int i = 0; i < np; i++) {
1869
+ ComputeParallax(ts[i], t0, Et);
1870
+
1871
+ tn = (ts[i] - t01) * tE_inv + pai1*Et[0] + pai2*Et[1];
1872
+ u0 = u1 + pai1*Et[1] - pai2*Et[0];
1873
+ u = tn*tn + u0*u0;
1874
+
1875
+ y1s[i] = -tn;
1876
+ y2s[i] = -u0;
1877
+ mags[i] = (u + 2) / sqrt(u*(u + 4));
1878
+
1879
+ tn = (ts[i] - t02) * tE_inv + pai1*Et[0] + pai2*Et[1];
1880
+ u0 = u2 + pai1*Et[1] - pai2*Et[0];
1881
+ u = tn*tn + u0*u0;
1882
+
1883
+ mags[i] += FR*(u + 2) / sqrt(u*(u + 4));
1884
+ mags[i] /= (1 + FR);
1885
+ }
1886
+ }
1887
+
1888
+
1889
+ void VBBinaryLensing::BinSourceLightCurveXallarap(double *pr, double *ts, double *mags, double *y1s, double *y2s,double *seps, int np) {
1890
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), tn, u, u0, pai1 = pr[6], pai2 = pr[7], q = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11];
1891
+ double th,Cth,Sth;
1892
+ double Et[2];
1893
+ double s,s_true,w, phi0, inc, phi, Cinc, Sinc, Cphi, Sphi, Cphi0, Sphi0, COm, SOm;
1894
+ double w13, w123, den, den0,du0,dt0;
1895
+ t0old = 0;
1896
+
1897
+ s = sqrt((u1 - u2)*(u1 - u2) + (t01 - t02)*(t01 - t02) * (tE_inv*tE_inv));
1898
+ th = atan2((u1 - u2) , (tE_inv*(t01 - t02)));
1899
+ Cth = cos(th);
1900
+ Sth = sin(th);
1901
+ u0 = (u1 + u2*q) / (1 + q);
1902
+ t0 = (t01 + t02*q) / (1 + q);
1903
+
1904
+ w13 = w1*w1 + w3*w3;
1905
+ w123 = sqrt(w13 + w2*w2);
1906
+ w13 = sqrt(w13);
1907
+ if (w13>1.e-8) {
1908
+ w3 = (w3>1.e-8) ? w3 : 1.e-8;
1909
+ w = w3*w123 / w13;
1910
+ inc = acos(w2*w3 / w13 / w123);
1911
+ phi0 = atan2(-w1*w123, w3*w13);
1912
+ }
1913
+ else {
1914
+ w = w2;
1915
+ inc = 0.;
1916
+ phi0 = 0.;
1917
+ }
1918
+ Cphi0 = cos(phi0);
1919
+ Sphi0 = sin(phi0);
1920
+ Cinc = cos(inc);
1921
+ Sinc = sin(inc);
1922
+ den0 = sqrt(Cphi0*Cphi0 + Cinc*Cinc*Sphi0*Sphi0);
1923
+ s_true = s / den0;
1924
+ COm = (Cphi0*Cth + Cinc*Sth*Sphi0) / den0;
1925
+ SOm = (Cphi0*Sth - Cinc*Cth*Sphi0) / den0;
1926
+
1927
+
1928
+ for (int i = 0; i < np; i++) {
1929
+ ComputeParallax(ts[i], t0, Et);
1930
+
1931
+ phi = (ts[i] - t0_par)*w + phi0;
1932
+ Cphi = cos(phi);
1933
+ Sphi = sin(phi);
1934
+ den = sqrt(Cphi*Cphi + Cinc*Cinc*Sphi*Sphi);
1935
+ seps[i] = s_true*den;
1936
+
1937
+ dt0 = s_true*(COm*Cphi-Cinc*SOm*Sphi)/(1+q)*q; //Position of the primary component with respect to center of mass
1938
+ du0 = s_true*(SOm*Cphi + Cinc*COm*Sphi) / (1 + q)*q;
1939
+
1940
+ tn= -((ts[i] - t0_par) * tE_inv + dt0 + pai1*Et[0] + pai2*Et[1]);
1941
+ u= -(u0+du0 + pai1*Et[1] - pai2*Et[0]);
1942
+ y1s[i] = tn;
1943
+ y2s[i] = u;
1944
+ u = tn*tn + u*u;
1945
+
1946
+ mags[i] = (u + 2) / sqrt(u*(u + 4));
1947
+
1948
+ tn =-( (ts[i] - t0_par) * tE_inv -dt0/q + pai1*Et[0] + pai2*Et[1]); // Position of the secondary component
1949
+ u =-( u0 - du0/q + pai1*Et[1] - pai2*Et[0]);
1950
+ u = tn*tn + u*u;
1951
+
1952
+ mags[i] += FR*(u + 2) / sqrt(u*(u + 4));
1953
+ mags[i] /= (1 + FR);
1954
+ }
1955
+ }
1956
+
1957
+
1958
+ void VBBinaryLensing::BinSourceExtLightCurve(double* pr, double* ts, double* mags, double* y1s, double* y2s, int np) {
1959
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), rho = exp(pr[6]), rho2, tn, u;
1960
+
1961
+ for (int i = 0; i < np; i++) {
1962
+ tn = (ts[i] - t01) * tE_inv;
1963
+ u = tn * tn + u1 * u1;
1964
+
1965
+ y1s[i] = -tn;
1966
+ y2s[i] = -u1;
1967
+ mags[i] = ESPLMag2(sqrt(u),rho);
1968
+
1969
+ tn = (ts[i] - t02) * tE_inv;
1970
+ u = tn * tn + u2 * u2;
1971
+ rho2 = rho * pow(FR, mass_radius_exponent / mass_luminosity_exponent);
1972
+ mags[i] += FR * ESPLMag2(sqrt(u), rho2);
1973
+ mags[i] /= (1 + FR);
1974
+
1975
+ }
1976
+
1977
+ }
1978
+
1979
+ void VBBinaryLensing::BinSourceBinLensXallarap(double* pr, double* ts, double* mags, double* y1s, double* y2s, int np) {
1980
+ double s = exp(pr[0]), q = exp(pr[1]), rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), u0;
1981
+ double salpha = sin(pr[3]), calpha = cos(pr[3]), xi1 = pr[7], xi2 = pr[8], omega = pr[9], inc = pr[10], phi = pr[11], qs = exp(pr[12]);
1982
+
1983
+ double Xal[2], phit, disp[2], Xal2[2], disp2[2];
1984
+ double Mag, Mag2, u02, rho2, tn2, y1s2, y2s2, qs4;
1985
+
1986
+
1987
+
1988
+ if (t0_par_fixed == 0) t0_par = pr[6];
1989
+
1990
+
1991
+ for (int i = 0; i < np; i++) {
1992
+
1993
+ phit = omega * (ts[i] - t0_par);
1994
+
1995
+ disp[0] = sin(inc) * (-cos(phi) + cos(phi + phit) + phit * sin(phi));
1996
+
1997
+ disp[1] = -phit * cos(phi) - sin(phi) + sin(phi + phit);
1998
+
1999
+ Xal[0] = xi1 * disp[0] + xi2 * disp[1];
2000
+ Xal[1] = xi2 * disp[0] - xi1 * disp[1];
2001
+ tn = (ts[i] - pr[6]) * tE_inv + Xal[0];
2002
+ u0 = pr[2] + Xal[1];
2003
+ y1s[i] = u0 * salpha - tn * calpha;
2004
+ y2s[i] = -u0 * calpha - tn * salpha;
2005
+ Mag = BinaryMag2(s, q, y1s[i], y2s[i], rho);
2006
+
2007
+ disp2[0] = -sin(inc) * (cos(phi) + cos(phi + phit) / qs - phit * sin(phi));
2008
+
2009
+ disp2[1] = phit * cos(phi) + sin(phi) + sin(phi + phit) / qs;
2010
+
2011
+ Xal2[0] = xi1 * disp2[0] - xi2 * disp2[1];
2012
+ Xal2[1] = xi2 * disp2[0] + xi1 * disp2[1];
2013
+ tn2 = (ts[i] - pr[6]) * tE_inv + Xal2[0];
2014
+ u02 = pr[2] + Xal2[1];
2015
+ y1s2 = u02 * salpha - tn2 * calpha;
2016
+ y2s2 = -u02 * calpha - tn2 * salpha;
2017
+ rho2 = rho * pow(qs, mass_radius_exponent);
2018
+ Mag2 = BinaryMag2(s, q, y1s2, y2s2, rho2);
2019
+ qs4 = pow(qs, mass_luminosity_exponent);
2020
+ mags[i] = (Mag + qs4 * Mag2) / (1 + qs4);
2021
+ }
2022
+ }
2023
+
2024
+ void VBBinaryLensing::BinSourceSingleLensXallarap(double* pr, double* ts, double* mags, double* y1s, double* y2s, double* y1s2, double* y2s2, int np) {
2025
+ double t0 = pr[1], rho = exp(pr[3]), tn, tE_inv = exp(-pr[2]), u0;
2026
+ double xi1 = pr[4], xi2 = pr[5], omega = pr[6], inc = pr[7], phi = pr[8], qs = exp(pr[9]);
2027
+
2028
+ double Xal[2], phit, disp[2], Xal2[2], disp2[2];
2029
+ double Mag, Mag2, u02, rho2, tn2, qs4, u, u2;
2030
+
2031
+
2032
+
2033
+ t0_par = pr[1];
2034
+
2035
+
2036
+ for (int i = 0; i < np; i++) {
2037
+
2038
+ phit = omega * (ts[i] - t0_par);
2039
+
2040
+ disp[0] = cos(inc) * (-cos(phi) + cos(phi + phit) + phit * sin(phi));
2041
+
2042
+ disp[1] = -phit * cos(phi) - sin(phi) + sin(phi + phit);
2043
+
2044
+ Xal[0] = xi1 * disp[0] + xi2 * disp[1];
2045
+ Xal[1] = xi2 * disp[0] - xi1 * disp[1];
2046
+ tn = (ts[i] - pr[1]) * tE_inv + Xal[0];
2047
+ u0 = pr[0] + Xal[1];
2048
+ u = sqrt(tn * tn + u0 * u0);
2049
+
2050
+ y1s[i] = -tn;
2051
+ y2s[i] = -u0;
2052
+ Mag = ESPLMag2(u, rho); /*If you want only the second source put =0, otherwise replace ESPLMag2(u, rho);*/
2053
+
2054
+
2055
+ disp2[0] = -cos(inc) * (cos(phi) + cos(phi + phit) / qs - phit * sin(phi));
2056
+
2057
+ disp2[1] = phit * cos(phi) + sin(phi) + sin(phi + phit) / qs;
2058
+
2059
+ Xal2[0] = xi1 * disp2[0] - xi2 * disp2[1];
2060
+ Xal2[1] = xi2 * disp2[0] + xi1 * disp2[1];
2061
+ tn2 = (ts[i] - pr[1]) * tE_inv + Xal2[0];
2062
+ u02 = pr[0] + Xal2[1];
2063
+ u2 = sqrt(tn2 * tn2 + u02 * u02);
2064
+ y1s2[i] = -tn2;
2065
+ y2s2[i] = -u02;
2066
+ rho2 = rho * pow(qs, mass_radius_exponent);
2067
+ Mag2 = ESPLMag2(u2, rho2); /*If you want only the second source put =0, otherwise replace ESPLMag2(u2, rho2);*/
2068
+ qs4 = pow(qs, mass_luminosity_exponent);
2069
+ mags[i] = (Mag + qs4 * Mag2) / (1 + qs4);
2070
+ }
2071
+ }
2072
+
2073
+ //////////////////////////////
2074
+ //////////////////////////////
2075
+ ////////Old (v1) light curve functions
2076
+ //////////////////////////////
2077
+ //////////////////////////////
2078
+
2079
+
2080
+ double VBBinaryLensing::PSPLLightCurve(double *pr, double t) {
2081
+ double u0 = exp(pr[0]), t0 = pr[2], tE_inv = exp(-pr[1]), tn, u;
2082
+
2083
+ tn = (t - t0) *tE_inv;
2084
+ u = tn*tn + u0*u0;
2085
+
2086
+ y_1 = -tn;
2087
+ y_2 = -u0;
2088
+ return (u + 2) / sqrt(u*(u + 4));
2089
+
2090
+ }
2091
+
2092
+
2093
+ double VBBinaryLensing::PSPLLightCurveParallax(double *pr, double t) {
2094
+ double u0 = pr[0], t0 = pr[2], tE_inv = exp(-pr[1]), tn, u, u1, pai1 = pr[3], pai2 = pr[4];
2095
+ double Et[2];
2096
+
2097
+ ComputeParallax(t, t0, Et);
2098
+ tn = (t - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
2099
+ u1 = u0 + pai1*Et[1] - pai2*Et[0];
2100
+ u = tn*tn + u1*u1;
2101
+
2102
+ y_1 = -tn;
2103
+ y_2 = -u1;
2104
+ return (u + 2) / sqrt(u*(u + 4));
2105
+
2106
+ }
2107
+
2108
+
2109
+ double VBBinaryLensing::ESPLLightCurve(double *pr, double t) {
2110
+ double u0 = exp(pr[0]), t0 = pr[2], tE_inv = exp(-pr[1]), tn, u, rho = exp(pr[3]);
2111
+
2112
+ tn = (t - t0) *tE_inv;
2113
+ u = sqrt(tn*tn + u0*u0);
2114
+
2115
+ y_1 = -tn;
2116
+ y_2 = -u0;
2117
+ return ESPLMag2(u, rho);
2118
+
2119
+ }
2120
+
2121
+ double VBBinaryLensing::ESPLLightCurveParallax(double *pr, double t) {
2122
+ double u0 = pr[0], t0 = pr[2], tE_inv = exp(-pr[1]), tn, u, u1, rho = exp(pr[3]), pai1 = pr[4], pai2 = pr[5];
2123
+ double Et[2];
2124
+
2125
+ ComputeParallax(t, t0, Et);
2126
+ tn = (t - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
2127
+ u1 = u0 + pai1*Et[1] - pai2*Et[0];
2128
+ u = sqrt(tn*tn + u1*u1);
2129
+
2130
+ y_1 = -tn;
2131
+ y_2 = -u1;
2132
+ return ESPLMag2(u, rho);
2133
+
2134
+ }
2135
+
2136
+
2137
+ double VBBinaryLensing::BinaryLightCurve(double *pr, double t) {
2138
+ double s = exp(pr[0]), q = exp(pr[1]), rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]);
2139
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
2140
+
2141
+ tn = (t - pr[6]) * tE_inv;
2142
+ y_1 = pr[2] * salpha - tn*calpha;
2143
+ y_2 = -pr[2] * calpha - tn*salpha;
2144
+ return BinaryMag2(s, q, y_1, y_2, rho);
2145
+
2146
+ }
2147
+
2148
+
2149
+ double VBBinaryLensing::BinaryLightCurveW(double *pr, double t) {
2150
+ double s = exp(pr[0]), q = exp(pr[1]), rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), t0, u0;
2151
+ double salpha = sin(pr[3]), calpha = cos(pr[3]), xc;
2152
+
2153
+ xc = (s - 1 / s) / (1 + q);
2154
+ if (xc<0) xc = 0.;
2155
+ t0 = pr[6] + xc*calpha / tE_inv;
2156
+ u0 = pr[2] + xc*salpha;
2157
+
2158
+ tn = (t - t0) * tE_inv;
2159
+ y_1 = u0 * salpha - tn*calpha;
2160
+ y_2 = -u0 * calpha - tn*salpha;
2161
+ return BinaryMag2(s, q, y_1, y_2, rho);
2162
+
2163
+ }
2164
+
2165
+
2166
+ double VBBinaryLensing::BinaryLightCurveParallax(double *pr, double t) {
2167
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], rho = exp(pr[4]), tn, u, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8];
2168
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
2169
+ double Et[2];
2170
+
2171
+ ComputeParallax(t, t0, Et);
2172
+ tn = (t - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
2173
+ u = u0 + pai1*Et[1] - pai2*Et[0];
2174
+ y_1 = u * salpha - tn*calpha;
2175
+ y_2 = -u * calpha - tn*salpha;
2176
+ return BinaryMag2(s, q, y_1, y_2, rho);
2177
+
2178
+ }
2179
+
2180
+
2181
+
2182
+
2183
+ double VBBinaryLensing::BinaryLightCurveOrbital(double *pr, double t) {
2184
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11];
2185
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
2186
+ double Et[2];
2187
+ double w, phi0, inc, phi, Cinc, Sinc, Cphi, Sphi, Cphi0, Sphi0, COm, SOm, s_true;
2188
+ double w13, w123, den, den0, u;
2189
+
2190
+ w13 = w1*w1 + w3*w3;
2191
+ w123 = sqrt(w13 + w2*w2);
2192
+ w13 = sqrt(w13);
2193
+ if (w13>1.e-8) {
2194
+ w3 = (w3>1.e-8) ? w3 : 1.e-8;
2195
+ w = w3*w123 / w13;
2196
+ inc = acos(w2*w3 / w13 / w123);
2197
+ phi0 = atan2(-w1*w123, w3*w13);
2198
+ }
2199
+ else {
2200
+ w = w2;
2201
+ inc = 0.;
2202
+ phi0 = 0.;
2203
+ }
2204
+
2205
+ Cphi0 = cos(phi0);
2206
+ Sphi0 = sin(phi0);
2207
+ Cinc = cos(inc);
2208
+ Sinc = sin(inc);
2209
+ den0 = sqrt(Cphi0*Cphi0 + Cinc*Cinc*Sphi0*Sphi0);
2210
+ s_true = s / den0;
2211
+ COm = (Cphi0*calpha + Cinc*salpha*Sphi0) / den0;
2212
+ SOm = (Cphi0*salpha - Cinc*calpha*Sphi0) / den0;
2213
+
2214
+ ComputeParallax(t, t0, Et);
2215
+
2216
+ phi = (t - t0_par)*w + phi0;
2217
+ Cphi = cos(phi);
2218
+ Sphi = sin(phi);
2219
+ den = sqrt(Cphi*Cphi + Cinc*Cinc*Sphi*Sphi);
2220
+ av = s_true*den;
2221
+
2222
+ u = u0 + pai1*Et[1] - pai2*Et[0];
2223
+ tn = (t - t0) * tE_inv + pai1*Et[0] + pai2*Et[1];
2224
+ y_1 = (Cphi*(u*SOm - tn*COm) + Cinc*Sphi*(u*COm + tn*SOm)) / den;
2225
+ y_2 = (-Cphi*(u*COm + tn*SOm) - Cinc*Sphi*(tn*COm - u*SOm)) / den;
2226
+ return BinaryMag2(av, q, y_1, y_2, rho);
2227
+ }
2228
+
2229
+ double VBBinaryLensing::BinaryLightCurveKepler(double *pr, double t) {
2230
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], alpha = pr[3], rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11], szs = pr[12], ar = pr[13]+1.e-8;
2231
+ double Et[2];
2232
+ double u, w22, w11, w33, w12, w23, szs2, ar2, EE, dE;
2233
+ double wt2, smix, sqsmix, e, h, snu, co1EE0, co2EE0, cosE, sinE, co1tperi, tperi, EE0, M, a, St, psi, dM, conu, n;
2234
+ double arm1, arm2;
2235
+ double X[3], Y[3], Z[3], r[2], x[2];
2236
+ t0old = 0;
2237
+
2238
+ smix = 1 + szs * szs;
2239
+ sqsmix = sqrt(smix);
2240
+ w22 = w2 * w2;
2241
+ w11 = w1 * w1;
2242
+ w33 = w3 * w3;
2243
+ w12 = w11 + w22;
2244
+ w23 = w22 + w33;
2245
+ wt2 = w12 + w33;
2246
+
2247
+ szs2 = szs * szs;
2248
+ ar2 = ar * ar;
2249
+ arm1 = ar - 1;
2250
+ arm2 = 2 * ar - 1;
2251
+ n = sqrt(wt2 / arm2 / smix) / ar;
2252
+ Z[0] = -szs * w2;
2253
+ Z[1] = szs * w1 - w3;
2254
+ Z[2] = w2;
2255
+ h = sqrt(Z[0] * Z[0] + Z[1] * Z[1] + Z[2] * Z[2]);
2256
+ for (int i = 0; i < 3; i++) Z[i] /= h;
2257
+ X[0] = -ar * w11 + arm1 * w22 - arm2 * szs*w1*w3 + arm1 * w33;
2258
+ X[1] = -arm2 * w2*(w1 + szs * w3);
2259
+ X[2] = arm1 * szs*w12 - arm2 * w1*w3 - ar * szs*w33;
2260
+ e = sqrt(X[0] * X[0] + X[1] * X[1] + X[2] * X[2]);
2261
+ for (int i = 0; i < 3; i++) X[i] /= e;
2262
+ e /= ar * sqsmix*wt2;
2263
+ Y[0] = Z[1] * X[2] - Z[2] * X[1];
2264
+ Y[1] = Z[2] * X[0] - Z[0] * X[2];
2265
+ Y[2] = Z[0] * X[1] - Z[1] * X[0];
2266
+
2267
+ conu = (X[0] + X[2] * szs) / sqsmix;
2268
+ co1EE0 = conu + e;
2269
+ co2EE0 = 1 + e * conu;
2270
+ cosE = co1EE0 / co2EE0;
2271
+ EE0 = acos(cosE);
2272
+ snu = (Y[0] + Y[2] * szs);
2273
+ EE0 *= (snu > 0) ? 1 : -1;
2274
+ sinE = sqrt(1 - cosE * cosE)*((snu > 0) ? 1 : -1);
2275
+ co1tperi = e * sinE;
2276
+ tperi = t0_par - (EE0 - co1tperi) / n;
2277
+
2278
+ ComputeParallax(t, t0, Et);
2279
+ M = n * (t - tperi);
2280
+ EE = M + e * sin(M);
2281
+ dE = 1;
2282
+ while (fabs(dE) > 1.e-8) {
2283
+ dM = M - (EE - e * sin(EE));
2284
+ dE = dM / (1 - e * cos(EE));
2285
+ EE += dE;
2286
+ }
2287
+
2288
+ a = ar * s*sqrt(smix);
2289
+
2290
+ r[0] = a * (cos(EE) - e);
2291
+ r[1] = a * sqrt(1 - e * e)*sin(EE);
2292
+ x[0] = r[0] * X[0] + r[1] * Y[0]; // (coX1*x[1] + coX2 * y[1] / h) / coX;
2293
+ x[1] = r[0] * X[1] + r[1] * Y[1]; //(coY1*x[1] + y[1] * coY2 / h) / coX;
2294
+ St = sqrt(x[0] * x[0] + x[1] * x[1]);
2295
+ psi = atan2(x[1], x[0]);// +((ar > 1) ? 0 : M_PI);
2296
+
2297
+ u = u0 + pai1 * Et[1] - pai2 * Et[0];
2298
+ tn = (t - t0) * tE_inv + pai1 * Et[0] + pai2 * Et[1];
2299
+ y_1 = -tn * cos(alpha + psi) + u * sin(alpha + psi);
2300
+ y_2 = -u * cos(alpha + psi) - tn * sin(alpha + psi);
2301
+
2302
+ return BinaryMag2(St, q, y_1, y_2, rho);
2303
+
2304
+ }
2305
+
2306
+ //double VBBinaryLensing::BinaryLightCurveKepler(double *pr, double t) {
2307
+ // double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], alpha = pr[3], rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), t0 = pr[6], pai1 = pr[7], pai2 = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11], szs = pr[12], ar = pr[13];
2308
+ // double Et[2];
2309
+ // double u, w22, w11, w33, w12, w23, szs2, ar2, coe2, coX, coX1, coX2, coY1, coY2, EE, dE;
2310
+ // double wt2, smix, e, h, co1e, co1nu, co2nu, co1EE0, co2EE0, co1tperi, tperi, EE0, nu, M, a, St, psi, dM, conu, n;
2311
+ // double x[3], y[3];
2312
+ // t0old = 0;
2313
+ //
2314
+ // wt2 = w1 * w1 + w2 * w2 + w3 * w3;
2315
+ // smix = 1 + szs * szs;
2316
+ // w22 = w2 * w2;
2317
+ // w11 = w1 * w1;
2318
+ //
2319
+ // w33 = w3 * w3;
2320
+ // w12 = w11 + w22;
2321
+ // w23 = w22 + w33;
2322
+ // szs2 = szs * szs;
2323
+ // ar2 = ar * ar;
2324
+ // n = sqrt(wt2) / (ar*sqrt(-1 + 2 * ar)*sqrt(smix));
2325
+ // h = sqrt((smix)*w22 + (szs*w1 - w3)*(szs*w1 - w3));
2326
+ // co1e = (1 - ar)*(1 - ar) + ar2 * szs2 + (-1 + 2 * ar)*(w11*(1 - szs2) - szs2 * w22 + 2 * szs*w1*w3) / wt2;
2327
+ // coe2 = ar2 * (smix);
2328
+ // e = sqrt(co1e) / sqrt(coe2);
2329
+ // co1nu = (-1 + 2 * ar)*sqrt(smix)*(w1 + szs * w3)*(szs2*(w12)-2 * szs*w1*w3 + w23);
2330
+ // co2nu = ar * e*h*(smix)*sqrt((smix))*wt2;
2331
+ // nu = asin(co1nu / co2nu);
2332
+ // conu = cos(nu);
2333
+ // co1EE0 = conu + e;
2334
+ // co2EE0 = 1 + e * conu;
2335
+ // EE0 = acos(co1EE0 / co2EE0);
2336
+ // co1tperi = e * sin(EE0);
2337
+ // tperi = t0_par - (EE0 - co1tperi) / n;
2338
+ // coX = ar * e*sqrt(smix)*wt2;
2339
+ // coX1 = -ar * w11 + (-1 + ar)*w22 + (1 - 2 * ar)*szs*w1*w3 + (-1 + ar)*w33;
2340
+ // coX2 = (-1 + 2 * ar)*w1*w23 + szs2 * w1*((-1 + ar)*w12 - ar * w33) + szs * w3*((2 - 3 * ar)*w11 + ar * w23);
2341
+ // coY1 = -(-1 + 2 * ar)*w2*(w1 + szs * w3);
2342
+ // coY2 = w2 * (-szs2 * w12 + 2 * szs*w1*w3 - w23 + ar * (-4 * szs*w1*w3 + szs2 * (w12 - w33) + (-w11 + w23)));
2343
+ //
2344
+ // ComputeParallax(t, t0, Et);
2345
+ // M = n * (t - tperi);
2346
+ // EE = M + e * sin(M);
2347
+ // dE = 1;
2348
+ // while (fabs(dE) > 1.e-8) {
2349
+ // dM = M - (EE - e * sin(EE));
2350
+ // dE = dM / (1 - e * cos(EE));
2351
+ // EE += dE;
2352
+ // }
2353
+ //
2354
+ // a = ar * s*sqrt(smix);
2355
+ //
2356
+ // x[1] = a * (cos(EE) - e);
2357
+ // y[1] = a * sqrt(1 - e * e)*sin(EE);
2358
+ // x[2] = (coX1*x[1] + coX2 * y[1] / h) / coX;
2359
+ // y[2] = (coY1*x[1] + y[1] * coY2 / h) / coX;
2360
+ // St = sqrt(x[2] * x[2] + y[2] * y[2]);
2361
+ // psi = atan2(y[2], x[2])+ ((ar>1)? 0 : M_PI);
2362
+ // u = u0 + pai1 * Et[1] - pai2 * Et[0];
2363
+ // tn = (t - t0) * tE_inv + pai1 * Et[0] + pai2 * Et[1];
2364
+ // y_1 = -tn * cos(alpha + psi) + u * sin(alpha + psi);
2365
+ // y_2 = -u * cos(alpha + psi) - tn * sin(alpha + psi);
2366
+ //
2367
+ // return BinaryMag2(St, q, y_1, y_2, rho);
2368
+ //
2369
+ //}
2370
+
2371
+ double VBBinaryLensing::BinSourceLightCurve(double *pr, double t) {
2372
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), tn, u,mag;
2373
+
2374
+ tn = (t - t01) * tE_inv;
2375
+ u = tn*tn + u1*u1;
2376
+
2377
+ y_1 = -tn;
2378
+ y_2 = -u1;
2379
+ mag = (u + 2) / sqrt(u*(u + 4));
2380
+
2381
+ tn = (t - t02) * tE_inv;
2382
+ u = tn*tn + u2*u2;
2383
+
2384
+ mag += FR*(u + 2) / sqrt(u*(u + 4));
2385
+ mag /= (1 + FR);
2386
+
2387
+ return mag;
2388
+
2389
+ }
2390
+
2391
+ double VBBinaryLensing::BinSourceLightCurveParallax(double *pr, double t) {
2392
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), tn, u, u0, pai1 = pr[6], pai2 = pr[7], w1 = pr[8], w2 = pr[9], w3 = pr[10];
2393
+ double Et[2],mag;
2394
+
2395
+ ComputeParallax(t, t0, Et);
2396
+
2397
+ tn = (t - t01) * tE_inv + pai1*Et[0] + pai2*Et[1];
2398
+ u0 = u1 + pai1*Et[1] - pai2*Et[0];
2399
+ u = tn*tn + u0*u0;
2400
+
2401
+ y_1 = -tn;
2402
+ y_2 = -u0;
2403
+ mag = (u + 2) / sqrt(u*(u + 4));
2404
+
2405
+ tn = (t - t02) * tE_inv + pai1*Et[0] + pai2*Et[1];
2406
+ u0 = u2 + pai1*Et[1] - pai2*Et[0];
2407
+ u = tn*tn + u0*u0;
2408
+
2409
+ mag += FR*(u + 2) / sqrt(u*(u + 4));
2410
+ mag /= (1 + FR);
2411
+
2412
+ return mag;
2413
+ }
2414
+
2415
+
2416
+ double VBBinaryLensing::BinSourceLightCurveXallarap(double *pr, double t) {
2417
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), tn, u, u0, pai1 = pr[6], pai2 = pr[7], q = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11];
2418
+ double th, Cth, Sth;
2419
+ double Et[2],mag;
2420
+ double s, s_true, w, phi0, inc, phi, Cinc, Sinc, Cphi, Sphi, Cphi0, Sphi0, COm, SOm;
2421
+ double w13, w123, den, den0, du0, dt0;
2422
+
2423
+ s = sqrt((u1 - u2)*(u1 - u2) + (t01 - t02)*(t01 - t02) * (tE_inv*tE_inv));
2424
+ th = atan2((u1 - u2), (tE_inv*(t01 - t02)));
2425
+ Cth = cos(th);
2426
+ Sth = sin(th);
2427
+ u0 = (u1 + u2*q) / (1 + q);
2428
+ t0 = (t01 + t02*q) / (1 + q);
2429
+
2430
+ w13 = w1*w1 + w3*w3;
2431
+ w123 = sqrt(w13 + w2*w2);
2432
+ w13 = sqrt(w13);
2433
+ if (w13>1.e-8) {
2434
+ w3 = (w3>1.e-8) ? w3 : 1.e-8;
2435
+ w = w3*w123 / w13;
2436
+ inc = acos(w2*w3 / w13 / w123);
2437
+ phi0 = atan2(-w1*w123, w3*w13);
2438
+ }
2439
+ else {
2440
+ w = w2;
2441
+ inc = 0.;
2442
+ phi0 = 0.;
2443
+ }
2444
+ Cphi0 = cos(phi0);
2445
+ Sphi0 = sin(phi0);
2446
+ Cinc = cos(inc);
2447
+ Sinc = sin(inc);
2448
+ den0 = sqrt(Cphi0*Cphi0 + Cinc*Cinc*Sphi0*Sphi0);
2449
+ s_true = s / den0;
2450
+ COm = (Cphi0*Cth + Cinc*Sth*Sphi0) / den0;
2451
+ SOm = (Cphi0*Sth - Cinc*Cth*Sphi0) / den0;
2452
+
2453
+ ComputeParallax(t, t0, Et);
2454
+
2455
+ phi = (t - t0_par)*w + phi0;
2456
+ Cphi = cos(phi);
2457
+ Sphi = sin(phi);
2458
+ den = sqrt(Cphi*Cphi + Cinc*Cinc*Sphi*Sphi);
2459
+ av = s_true*den;
2460
+
2461
+ dt0 = s_true*(COm*Cphi - Cinc*SOm*Sphi) / (1 + q)*q; //Position of the primary component with respect to center of mass
2462
+ du0 = s_true*(SOm*Cphi + Cinc*COm*Sphi) / (1 + q)*q;
2463
+
2464
+ tn = -((t - t0_par) * tE_inv - dt0 + pai1*Et[0] + pai2*Et[1]);
2465
+ u = -(u0 + du0 + pai1*Et[1] - pai2*Et[0]);
2466
+ y_1 = tn;
2467
+ y_2 = u;
2468
+ u = tn*tn + u*u;
2469
+
2470
+ mag = (u + 2) / sqrt(u*(u + 4));
2471
+
2472
+ tn = -((t - t0_par) * tE_inv + dt0 / q + pai1*Et[0] + pai2*Et[1]); // Position of the secondary component
2473
+ u = -(u0 - du0 / q + pai1*Et[1] - pai2*Et[0]);
2474
+ u = tn*tn + u*u;
2475
+
2476
+ mag += FR*(u + 2) / sqrt(u*(u + 4));
2477
+ mag /= (1 + FR);
2478
+
2479
+ return mag;
2480
+
2481
+ }
2482
+
2483
+
2484
+ double VBBinaryLensing::BinSourceExtLightCurve(double* pr, double t) {
2485
+ double u1 = pr[2], u2 = pr[3], t01 = pr[4], t02 = pr[5], tE_inv = exp(-pr[0]), FR = exp(pr[1]), rho = exp(pr[6]), rho2, tn, u, mag;
2486
+
2487
+ tn = (t - t01) * tE_inv;
2488
+ u = tn * tn + u1 * u1;
2489
+
2490
+ y_1 = -tn;
2491
+ y_2 = -u1;
2492
+ mag = ESPLMag2(sqrt(u), rho);
2493
+
2494
+ tn = (t - t02) * tE_inv;
2495
+ u = tn * tn + u2 * u2;
2496
+ rho2 = rho * pow(FR, mass_radius_exponent / mass_luminosity_exponent);
2497
+
2498
+ mag += FR * ESPLMag2(sqrt(u), rho2);
2499
+ mag /= (1 + FR);
2500
+
2501
+ return mag;
2502
+
2503
+ }
2504
+
2505
+
2506
+ double VBBinaryLensing::BinSourceBinLensXallarap(double* pr, double t) {
2507
+
2508
+ double s = exp(pr[0]), q = exp(pr[1]), rho = exp(pr[4]), tn, tE_inv = exp(-pr[5]), u0;
2509
+ double salpha = sin(pr[3]), calpha = cos(pr[3]), xi1 = pr[7], xi2 = pr[8], omega = pr[9], inc = pr[10], phi = pr[11], qs = exp(pr[12]);
2510
+
2511
+ double Xal[2], phit, disp[2], Xal2[2], disp2[2];
2512
+ double Mag, Mag2, u02, rho2, tn2, y1s2, y2s2, y1s, y2s, mags, qs4;
2513
+
2514
+
2515
+
2516
+ if (t0_par_fixed == 0) t0_par = pr[6];
2517
+
2518
+
2519
+
2520
+
2521
+ phit = omega * (t - t0_par);
2522
+
2523
+ disp[0] = cos(inc) * (-cos(phi) + cos(phi + phit) + phit * sin(phi));
2524
+
2525
+ disp[1] = -phit * cos(phi) - sin(phi) + sin(phi + phit);
2526
+
2527
+ Xal[0] = xi1 * disp[0] + xi2 * disp[1];
2528
+ Xal[1] = xi2 * disp[0] - xi1 * disp[1];
2529
+ tn = (t - pr[6]) * tE_inv + Xal[0];
2530
+ u0 = pr[2] + Xal[1];
2531
+ y1s = u0 * salpha - tn * calpha;
2532
+ y2s = -u0 * calpha - tn * salpha;
2533
+ Mag = BinaryMag2(s, q, y1s, y2s, rho);
2534
+
2535
+ disp2[0] = -cos(inc) * (cos(phi) + cos(phi + phit) / qs - phit * sin(phi));
2536
+
2537
+ disp2[1] = phit * cos(phi) + sin(phi) + sin(phi + phit) / qs;
2538
+
2539
+ Xal2[0] = xi1 * disp2[0] - xi2 * disp2[1];
2540
+ Xal2[1] = xi2 * disp2[0] + xi1 * disp2[1];
2541
+ tn2 = (t - pr[6]) * tE_inv + Xal2[0];
2542
+ u02 = pr[2] + Xal2[1];
2543
+ y1s2 = u02 * salpha - tn2 * calpha;
2544
+ y2s2 = -u02 * calpha - tn2 * salpha;
2545
+ rho2 = rho * pow(qs, mass_radius_exponent);
2546
+ Mag2 = BinaryMag2(s, q, y1s2, y2s2, rho2);
2547
+ qs4 = pow(qs, mass_luminosity_exponent);
2548
+ mags = (Mag + qs4*Mag2) / (1 + qs4);
2549
+
2550
+ return mags;
2551
+
2552
+
2553
+ }
2554
+
2555
+ double VBBinaryLensing::BinSourceSingleLensXallarap(double* pr, double t) {
2556
+
2557
+ double t0 = pr[1], rho = exp(pr[3]), tn, tE_inv = exp(-pr[2]), u0;
2558
+ double xi1 = pr[4], xi2 = pr[5], omega = pr[6], inc = pr[7], phi = pr[8], qs = exp(pr[9]);
2559
+
2560
+ double Xal[2], phit, disp[2], Xal2[2], disp2[2];
2561
+ double Mag, Mag2, u02, rho2, tn2, y1s2, y2s2, qs4, u, y1s, y2s, mags, u2;
2562
+
2563
+
2564
+
2565
+ t0_par = pr[1];
2566
+
2567
+ phit = omega * (t - t0_par);
2568
+
2569
+ disp[0] = cos(inc) * (-cos(phi) + cos(phi + phit) + phit * sin(phi));
2570
+
2571
+ disp[1] = -phit * cos(phi) - sin(phi) + sin(phi + phit);
2572
+
2573
+ Xal[0] = xi1 * disp[0] + xi2 * disp[1];
2574
+ Xal[1] = xi2 * disp[0] - xi1 * disp[1];
2575
+ tn = (t - pr[1]) * tE_inv + Xal[0];
2576
+ u0 = pr[0] + Xal[1];
2577
+ u = sqrt(tn * tn + u0 * u0);
2578
+
2579
+ y1s = -tn;
2580
+ y2s = -u0;
2581
+ Mag = ESPLMag2(u, rho); /*If you want only the second source put =0, otherwise replace ESPLMag2(u, rho);*/
2582
+
2583
+
2584
+ disp2[0] = -cos(inc) * (cos(phi) + cos(phi + phit) / qs - phit * sin(phi));
2585
+
2586
+ disp2[1] = phit * cos(phi) + sin(phi) + sin(phi + phit) / qs;
2587
+
2588
+ Xal2[0] = xi1 * disp2[0] - xi2 * disp2[1];
2589
+ Xal2[1] = xi2 * disp2[0] + xi1 * disp2[1];
2590
+ tn2 = (t - pr[1]) * tE_inv + Xal2[0];
2591
+ u02 = pr[0] + Xal2[1];
2592
+ u2 = sqrt(tn2 * tn2 + u02 * u02);
2593
+ y1s2 = -tn2;
2594
+ y2s2 = -u02;
2595
+ rho2 = rho * pow(qs, mass_radius_exponent);
2596
+ Mag2 = ESPLMag2(u2, rho2); /*If you want only the second source put =0, otherwise replace ESPLMag2(u2, rho2);*/
2597
+ qs4 = pow(qs, mass_luminosity_exponent);
2598
+ mags = (Mag + qs4 * Mag2) / (1 + qs4);
2599
+ return mags;
2600
+ }
2601
+
2602
+ double VBBinaryLensing::BinSourceBinLensPOX(double* pr, double t) {
2603
+ double s = exp(pr[0]), q = exp(pr[1]), u0 = pr[2], rho = exp(pr[4]), tE_inv = exp(-pr[5]), t0 = pr[6];
2604
+ double pai1 = pr[7], pai2 = pr[8], w1 = pr[9], w2 = pr[10], w3 = pr[11];
2605
+ double salpha = sin(pr[3]), calpha = cos(pr[3]);
2606
+ double Et[2];
2607
+ double tn, w, phi0, phil, incl, Cinc, Sinc, Cphi, Sphi, Cphi0, Sphi0, COm, SOm, s_true;
2608
+ double w13, w123, den, den0, u;
2609
+
2610
+ double xi1 = pr[12], xi2 = pr[13], omega = pr[14], inc = pr[15], phi = pr[16], qs = exp(pr[17]);
2611
+ double Xal[2], phit, disp[2], Xal2[2], disp2[2];
2612
+ double Mag, Mag2, u01, u02, rho2, tn1, tn2, mags, qs4;
2613
+
2614
+ w13 = w1 * w1 + w3 * w3;
2615
+ w123 = sqrt(w13 + w2 * w2);
2616
+ w13 = sqrt(w13);
2617
+ if (w13 > 1.e-8) {
2618
+ w3 = (w3 > 1.e-8) ? w3 : 1.e-8;
2619
+ w = w3 * w123 / w13;
2620
+ incl = acos(w2 * w3 / w13 / w123);
2621
+ phi0 = atan2(-w1 * w123, w3 * w13);
2622
+ }
2623
+ else {
2624
+ w = w2;
2625
+ incl = 0.;
2626
+ phi0 = 0.;
2627
+ }
2628
+
2629
+ Cphi0 = cos(phi0);
2630
+ Sphi0 = sin(phi0);
2631
+ Cinc = cos(incl);
2632
+ Sinc = sin(incl);
2633
+ den0 = sqrt(Cphi0 * Cphi0 + Cinc * Cinc * Sphi0 * Sphi0);
2634
+ s_true = s / den0;
2635
+ COm = (Cphi0 * calpha + Cinc * salpha * Sphi0) / den0;
2636
+ SOm = (Cphi0 * salpha - Cinc * calpha * Sphi0) / den0;
2637
+
2638
+ ComputeParallax(t, t0, Et);
2639
+
2640
+ phil = (t - t0_par) * w + phi0;
2641
+ Cphi = cos(phil);
2642
+ Sphi = sin(phil);
2643
+ den = sqrt(Cphi * Cphi + Cinc * Cinc * Sphi * Sphi);
2644
+ av = s_true * den;
2645
+ u = u0 + pai1 * Et[1] - pai2 * Et[0];
2646
+ tn = (t-t0)*tE_inv + pai1 * Et[0] + pai2 * Et[1];
2647
+
2648
+ phit = omega * (t - t0_par);
2649
+
2650
+ disp[0] = sin(inc) * (-cos(phi) + cos(phi + phit) + phit * sin(phi));
2651
+ disp[1] = -phit * cos(phi) - sin(phi) + sin(phi + phit);
2652
+ disp2[0] = -sin(inc) * (cos(phi) + cos(phi + phit) / qs - phit * sin(phi));
2653
+ disp2[1] = phit * cos(phi) + sin(phi) + sin(phi + phit) / qs;
2654
+
2655
+ Xal[0] = xi1 * disp[0] + xi2 * disp[1];
2656
+ Xal[1] = xi2 * disp[0] - xi1 * disp[1];
2657
+ Xal2[0] = xi1 * disp2[0] - xi2 * disp2[1];
2658
+ Xal2[1] = xi2 * disp2[0] + xi1 * disp2[1];
2659
+
2660
+ tn1 = tn + Xal[0];
2661
+ u01 = u + Xal[1];
2662
+ tn2 = tn + Xal2[0];
2663
+ u02 = u + Xal2[1];
2664
+ rho2 = rho * pow(qs, mass_radius_exponent);
2665
+ qs4 = pow(qs, mass_luminosity_exponent);
2666
+
2667
+
2668
+ /* y1s = u01 * salpha - tn1 * calpha;
2669
+ y2s = -u01 * calpha - tn1 * salpha;
2670
+ y1s2 = u02 * salpha - tn2 * calpha;
2671
+ y2s2 = -u02 * calpha - tn2 * salpha;*/
2672
+
2673
+ y_1 = (Cphi * (u02 * SOm - tn2 * COm) + Cinc * Sphi * (u02 * COm + tn2 * SOm)) / den;
2674
+ y_2 = (-Cphi * (u02 * COm + tn2 * SOm) - Cinc * Sphi * (tn2 * COm - u02 * SOm)) / den;
2675
+ Mag2 = BinaryMag2(av, q, y_1, y_2, rho2);
2676
+
2677
+ y_1 = (Cphi * (u01 * SOm - tn1 * COm) + Cinc * Sphi * (u01 * COm + tn1 * SOm)) / den;
2678
+ y_2 = (-Cphi * (u01 * COm + tn1 * SOm) - Cinc * Sphi * (tn1 * COm - u01 * SOm)) / den;
2679
+ Mag = BinaryMag2(av, q, y_1, y_2, rho);
2680
+
2681
+ mags = (Mag + qs4 * Mag2) / (1 + qs4);
2682
+
2683
+ return mags;
2684
+ }
2685
+
2686
+ ///////////////////////////////////////////////
2687
+ ///////////////////////////////////////////////
2688
+ ////////// Internal private functions
2689
+ ///////////////////////////////////////////////
2690
+ ///////////////////////////////////////////////
2691
+
2692
+ #define _Jacobians1 \
2693
+ z=zr[i];\
2694
+ dza=z-coefs[20];\
2695
+ za2 = dza*dza;\
2696
+ zb2=z*z;\
2697
+ J1= coefs[21]/za2+coefs[22]/zb2;\
2698
+ J1c=conj(J1);\
2699
+ dJ=1-J1*J1c;\
2700
+ J2=-2.*(coefs[21]/(za2*dza)+coefs[22]/(zb2*z));
2701
+
2702
+ #define _Jacobians2\
2703
+ dy = complex(-sin(theta->th), cos(theta->th))*coefs[23];\
2704
+ dz = (dy - J1c*conj(dy)) / dJ.re;\
2705
+ Prov->last->x1 -= coefs[11].re;\
2706
+ Prov->last->dJ = dJ.re;\
2707
+ Prov->last->d = dz;\
2708
+ Prov->last->J2 = J2;\
2709
+ Prov->last->ds = (imag(dy*dz*dz*J2) + coefs[23].re*coefs[23].re) / dJ.re;
2710
+
2711
+
2712
+ #define _Jacobians3\
2713
+ Prov->last->dJ = dJ.re;\
2714
+ J3=6.*(coefs[21]/(za2*za2)+coefs[22]/(zb2*zb2));\
2715
+ dJ2=dJ.re*dJ.re;\
2716
+ za2=J1c*J1c;\
2717
+ J3=J3*za2;\
2718
+ ob2=(J2.re*J2.re+J2.im*J2.im)*(6-6*dJ.re+dJ2);\
2719
+ J2=J2*J2*za2*J1c;\
2720
+ cq= 0.5*(fabs(ob2-6.*J2.re-2.*J3.re*dJ.re)+3*fabs(J2.im))/fabs(dJ.re*dJ2*dJ2);
2721
+
2722
+ #define _Jacobians4\
2723
+ zaltc=yc+coefs[21]/dza+coefs[22]/z;\
2724
+ za2=(zaltc-coefs[20]);\
2725
+ Jaltc=coefs[21]/(za2*za2)+coefs[22]/(zaltc*zaltc);\
2726
+ Jalt = conj(Jaltc);\
2727
+ JJalt2=(1-J1c*Jalt);\
2728
+ J3=J2*J1c*JJalt2;\
2729
+ J3=(J3-conj(J3)*Jalt)/(JJalt2*JJalt2*dJ.re);\
2730
+ cq=(dJ.re<-100)? 0.0 : (J3.re*J3.re+J3.im*J3.im);
2731
+
2732
+
2733
+ _curve* VBBinaryLensing::NewImages(complex yi, complex* coefs, _theta* theta) {
2734
+ static complex y, yc, z, zc, J1, J1c, dy, dz, dJ, J2, J3, dza, za2, zb2, zaltc, Jalt, Jaltc, JJalt2;
2735
+ static complex zr[5] = { 0.,0.,0.,0.,0. };
2736
+ static double dlmin = 1.0e-4, dlmax = 1.0e-3, good[5], dJ2, ob2, cq;
2737
+ static int worst1, worst2, worst3, bad, f1, checkJac;
2738
+ static double av = 0.0, m1v = 0.0, disim, disisso;
2739
+ static _curve* Prov;
2740
+ static _point* scan, * prin, * fifth, * left, * right, * center;
2741
+
2742
+ #ifdef _PRINT_TIMES
2743
+ static double tim0, tim1;
2744
+ #endif
2745
+
2746
+ y = yi + coefs[11];
2747
+ yc = conj(y);
2748
+
2749
+ // coefs[6]=a*a; coefs[7]=a*a*a; coefs[8]=m2*m2; coefs[9]=a*a*m2*m2; coefs[10]=a*m2; coefs[11]=a*m1; coefs[20]=a; coefs[21]=m1; coefs[22]=m2;
2750
+
2751
+ coefs[0] = coefs[9] * y;
2752
+ coefs[1] = coefs[10] * (coefs[20] * (coefs[21] + y * (2 * yc - coefs[20])) - 2 * y);
2753
+ coefs[2] = y * (1 - coefs[7] * yc) - coefs[20] * (coefs[21] + 2 * y * yc * (1 + coefs[22])) + coefs[6] * (yc * (coefs[21] - coefs[22]) + y * (1 + coefs[22] + yc * yc));
2754
+ coefs[3] = 2 * y * yc + coefs[7] * yc + coefs[6] * (yc * (2 * y - yc) - coefs[21]) - coefs[20] * (y + 2 * yc * (yc * y - coefs[22]));
2755
+ coefs[4] = yc * (2 * coefs[20] + y);
2756
+ coefs[4] = yc * (coefs[4] - 1) - coefs[20] * (coefs[4] - coefs[21]);
2757
+ coefs[5] = yc * (coefs[20] - yc);
2758
+
2759
+ bad = 1;
2760
+ disim = -1.;
2761
+ f1 = 0;
2762
+
2763
+ #ifdef _PRINT_TIMES
2764
+ tim0 = Environment::TickCount;
2765
+ #endif
2766
+ cmplx_roots_gen(zr, coefs, 5, true, true);
2767
+
2768
+ #ifdef _PRINT_TIMES
2769
+ tim1 = Environment::TickCount;
2770
+ inc += tim1 - tim0;
2771
+ #endif
2772
+ // apply lens equation to check if it is really solved
2773
+ for (int i = 0; i < 5; i++) {
2774
+ z = zr[i];
2775
+ zc = conj(z);
2776
+ good[i] = abs(_LL); // Lens equation check
2777
+ switch (i) {
2778
+ case 0:
2779
+ worst1 = i;
2780
+ break;
2781
+ case 1:
2782
+ if (good[i] > good[worst1]) {
2783
+ worst2 = worst1;
2784
+ worst1 = i;
2785
+ }
2786
+ else worst2 = i;
2787
+ break;
2788
+ case 2:
2789
+ if (good[i] > good[worst1]) {
2790
+ worst3 = worst2;
2791
+ worst2 = worst1;
2792
+ worst1 = i;
2793
+ }
2794
+ else if (good[i] > good[worst2]) {
2795
+ worst3 = worst2;
2796
+ worst2 = i;
2797
+ }
2798
+ else worst3 = i;
2799
+ break;
2800
+ default:
2801
+ if (good[i] > good[worst1]) {
2802
+ worst3 = worst2;
2803
+ worst2 = worst1;
2804
+ worst1 = i;
2805
+ }
2806
+ else if (good[i] > good[worst2]) {
2807
+ worst3 = worst2;
2808
+ worst2 = i;
2809
+ }
2810
+ else if (good[i] > good[worst3]) {
2811
+ worst3 = i;
2812
+ }
2813
+ }
2814
+ }
2815
+ Prov = new _curve;
2816
+ checkJac = 0;
2817
+ // if (!((good[worst3] < dlmin) && ((good[worst1] < dlmin) || (good[worst2] > dlmax)))) { // old check for unacceptable roots
2818
+
2819
+ // 3 good roots
2820
+ if (good[worst2] * dlmin > good[worst3]+1.e-12 ) {
2821
+ for (int i = 0; i < 5; i++) {
2822
+ if ((i != worst1) && (i != worst2)) {
2823
+ //if((i==worst3)&&(good[i]>dlmax)&&(good[worst2]>1.e2*good[worst3])){
2824
+ // zr[i]=(coefs[21].re<coefs[22].re)? 0.5*coefs[20]+coefs[21]/(0.5*coefs[20]-yc-coefs[22]/coefs[20]) : -0.5*coefs[20]+coefs[22]/(-0.5*coefs[20]-yc+coefs[21]/coefs[20]);
2825
+ //}
2826
+ Prov->append(zr[i].re, zr[i].im);
2827
+
2828
+ _Jacobians1
2829
+ if (theta->th >= 0) {
2830
+ _Jacobians2
2831
+ }
2832
+ else {
2833
+ _Jacobians3
2834
+ corrquad += cq;
2835
+ }
2836
+ checkJac += (fabs(Prov->last->dJ) > 1.e-7) ? _sign(Prov->last->dJ) : 10;
2837
+ Prov->last->theta = theta;
2838
+
2839
+ }
2840
+ }
2841
+ if (theta->th < 0) {
2842
+ dz = zr[worst2] - zr[worst1];
2843
+
2844
+ int i = worst1;
2845
+ _Jacobians1
2846
+ _Jacobians4
2847
+ corrquad2 = cq;
2848
+
2849
+ i = worst2;
2850
+ _Jacobians1
2851
+ _Jacobians4
2852
+ if (cq > corrquad2) corrquad2 = cq;
2853
+ //_Jacobians3
2854
+ //corrquad2 += 1/cq;
2855
+
2856
+ }
2857
+ else {
2858
+ theta->errworst = abs(zr[worst1] - zr[worst2]);
2859
+ }
2860
+
2861
+ }
2862
+ else {
2863
+ if (good[worst2]*dlmax > good[worst3] + 1.e-12 && theta->th>=0) { // Dubious cases. Better exclude them
2864
+ return Prov;
2865
+ }
2866
+ else { // 5 good roots
2867
+ f1 = 0;
2868
+ for (int i = 0; i < 5; i++) {
2869
+ Prov->append(zr[i].re, zr[i].im);
2870
+
2871
+ _Jacobians1
2872
+ if (theta->th >= 0) {
2873
+ _Jacobians2
2874
+ }
2875
+ else {
2876
+ _Jacobians3
2877
+ corrquad += cq;
2878
+ }
2879
+ checkJac += (fabs(Prov->last->dJ) > 1.e-7) ? _sign(Prov->last->dJ) : 10;
2880
+ Prov->last->theta = theta;
2881
+
2882
+ if (fabs(dJ.re) < 1.e-5) f1 = 1;
2883
+ }
2884
+ theta->errworst = -1.e100;
2885
+ // check Jacobians in ambiguous cases
2886
+ if (f1) {
2887
+ left = right = center = fifth = 0;
2888
+ dJ.re = 0;
2889
+ for (scan = Prov->first; scan; scan = scan->next) {
2890
+ if (_sign(scan->x2) == _sign(y.im)) {
2891
+ prin = scan;
2892
+ }
2893
+ else {
2894
+ dz.re = fabs(scan->dJ);
2895
+ if (dz.re > dJ.re) {
2896
+ fifth = scan;
2897
+ dJ.re = dz.re;
2898
+ }
2899
+ }
2900
+ }
2901
+ for (scan = Prov->first; scan; scan = scan->next) {
2902
+ if ((scan != prin) && (scan != fifth)) {
2903
+ if (left) {
2904
+ if (scan->x1 < left->x1) {
2905
+ if (left != right) {
2906
+ center = left;
2907
+ }
2908
+ left = scan;
2909
+ }
2910
+ else {
2911
+ if (scan->x1 > right->x1) {
2912
+ if (left != right) {
2913
+ center = right;
2914
+ }
2915
+ right = scan;
2916
+ }
2917
+ else {
2918
+ center = scan;
2919
+ }
2920
+ }
2921
+ }
2922
+ else {
2923
+ left = right = center = scan;
2924
+ }
2925
+ }
2926
+ }
2927
+ if (left->dJ > 0) left->dJ = -left->dJ;
2928
+ if (center->dJ < 0) center->dJ = -center->dJ;
2929
+ if (right->dJ > 0) right->dJ = -right->dJ;
2930
+ }
2931
+ }
2932
+ }
2933
+ if (checkJac != -1) {
2934
+ // printf("\ncheckJac!");
2935
+ if (theta->th < 0) {
2936
+ dJ = 0;
2937
+ for (scan = Prov->first; scan; scan = scan->next) {
2938
+ dJ = dJ+ 1 / fabs(scan->dJ);
2939
+ }
2940
+ if (fabs(dJ.re - 1) < Tol) {
2941
+ checkJac = -1;
2942
+ corrquad = 0;
2943
+ }
2944
+ }
2945
+ if(checkJac!=-1){
2946
+ _point* scan2;
2947
+ for (scan = Prov->first; scan; scan = scan2) {
2948
+ scan2 = scan->next;
2949
+ Prov->drop(scan);
2950
+ delete scan;
2951
+ }
2952
+ }
2953
+ }
2954
+ return Prov;
2955
+ }
2956
+
2957
+ void VBBinaryLensing::OrderImages(_sols *Sols, _curve *Newpts) {
2958
+ static double A[5][5];
2959
+ static _curve *cprec[5];
2960
+ static _curve *cpres[5];
2961
+ static _curve *cfoll[5];
2962
+ static _point *scan, *scan2, *scan3, *isso[2];
2963
+ static _curve *scurve, *scurve2;
2964
+
2965
+ _theta *theta;
2966
+ static double th, mi, cmp, cmp2,cmp_2,dx2,avgx2,avgx1,avg2x1,pref,d2x2,dx1,d2x1,avgwedgex1,avgwedgex2,parab1,parab2;
2967
+
2968
+ int nprec = 0, npres, nfoll = 0, issoc[2], ij;
2969
+
2970
+ theta = Newpts->first->theta;
2971
+ th = theta->th;
2972
+ theta->Mag = theta->prev->Mag = theta->maxerr = theta->prev->maxerr = 0;
2973
+ theta->astrox1 = theta->prev->astrox1 = theta->astrox2 = theta->prev->astrox2 = 0;
2974
+ if (Newpts->length == 3) {
2975
+ mi = theta->next->errworst - theta->errworst;
2976
+ if ((mi>theta->errworst) && (theta->prev->errworst>0.)) {
2977
+ theta->prev->maxerr = mi*mi;
2978
+ }
2979
+ mi = theta->prev->errworst - theta->errworst;
2980
+ if ((mi>theta->errworst) && (theta->next->errworst>0.)) {
2981
+ theta->maxerr = mi*mi;
2982
+ }
2983
+ }
2984
+
2985
+ // Per ciascuna immagine troviamo il punto in cui inserire i nuovi punti
2986
+ scurve = Sols->first;
2987
+ for (int i = 0; i<Sols->length; i++) {
2988
+ if (th<scurve->first->theta->th) {
2989
+ if (th>scurve->first->theta->prev->prev->th) {
2990
+ cfoll[nfoll] = scurve; // immagine coinvolta all'inizio
2991
+ nfoll++;
2992
+ scurve2 = scurve->next;
2993
+ Sols->drop(scurve);
2994
+ i--;
2995
+ scurve = scurve2;
2996
+ }
2997
+ else {
2998
+ scurve = scurve->next;
2999
+ }
3000
+ }
3001
+ else {
3002
+ if (th>scurve->last->theta->th) {
3003
+ if (th<scurve->last->theta->next->next->th) {
3004
+ cprec[nprec] = scurve; // immagine coinvolta alla fine
3005
+ nprec++;
3006
+ }
3007
+ }
3008
+ else {
3009
+ // immagine coinvolta al centro
3010
+ scan = scurve->last;
3011
+ while (scan->theta->th>th) {
3012
+ scan = scan->prev;
3013
+ }
3014
+ cfoll[nfoll] = scurve->divide(scan);
3015
+ nfoll++;
3016
+ cprec[nprec] = scurve;
3017
+ nprec++;
3018
+ }
3019
+ scurve = scurve->next;
3020
+ }
3021
+ }
3022
+ npres = Newpts->length;
3023
+
3024
+ //if((theta->th>4.7116917419)&&(theta->th<4.711691759)){
3025
+ // theta->th=theta->th;
3026
+ //}
3027
+ //if((theta->prev->th>4.7116917419)&&(theta->prev->th<4.711691759)){
3028
+ // theta->th=theta->th;
3029
+ //}
3030
+
3031
+
3032
+ // Caso di creazione nuove immagini//
3033
+
3034
+ if (nprec<npres) {
3035
+ mi = 1.e100;
3036
+ scan = Newpts->first;
3037
+ for (int i = 0; i<Newpts->length - 1; i++) {
3038
+ scan2 = scan->next;
3039
+ for (int j = i + 1; j<Newpts->length; j++) {
3040
+ cmp = (*scan2) - (*scan);
3041
+ if (cmp<mi) {
3042
+ mi = cmp;
3043
+ isso[0] = scan;
3044
+ isso[1] = scan2;
3045
+ }
3046
+ scan2 = scan2->next;
3047
+ }
3048
+ scan = scan->next;
3049
+ }
3050
+ Newpts->drop(isso[0]);
3051
+ Newpts->drop(isso[1]);
3052
+ scurve = new _curve(isso[0]);
3053
+ isso[0]->prev = isso[0]->next = 0;
3054
+ scurve2 = new _curve(isso[1]);
3055
+ isso[1]->prev = isso[1]->next = 0;
3056
+ scurve->partneratstart = scurve2;
3057
+ scurve2->partneratstart = scurve;
3058
+ Sols->append(scurve);
3059
+ Sols->append(scurve2);
3060
+ cpres[3] = scurve;
3061
+ cpres[4] = scurve2;
3062
+ scan = isso[0];
3063
+ scan2 = isso[1];
3064
+
3065
+ cmp2 = fabs(scan->d.re*scan2->d.re + scan->d.im*scan2->d.im);
3066
+ cmp = sqrt(mi / cmp2); // Delta theta tilde
3067
+
3068
+ cmp_2 = cmp*cmp;
3069
+ mi = cmp_2*cmp*0.04166666667;
3070
+ parab1 = -(-scan->ds + scan2->ds)*mi;
3071
+ parab2=-0.0833333333 * ((scan2->x1 - scan->x1) * (scan2->d.im + scan->d.im) - (scan2->x2 - scan->x2) * (scan2->d.re + scan->d.re)) * cmp;
3072
+ scurve->parabstart = 0.5 * (parab1 + parab2);
3073
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////astro: created image:
3074
+ if(astrometry){
3075
+ avgwedgex1=-(-scan->x1*scan->ds + scan2->x1*scan2->ds)*mi;
3076
+ avgwedgex2=-(-scan->x2*scan->ds + scan2->x2*scan2->ds)*mi;
3077
+ dx2=-(-scan->d.im+scan2->d.im);
3078
+ d2x2=dx2*dx2;
3079
+ dx1=-(-scan->d.re+scan2->d.re);
3080
+ d2x1=dx1*dx1;
3081
+ scurve->parabastrox1 =-0.125*d2x1*dx2*mi-avgwedgex1;
3082
+ scurve->parabastrox2 =-0.125*d2x2*dx1*mi+avgwedgex2;
3083
+ }
3084
+ #ifdef _PRINT_ERRORS
3085
+ printf("\n%le %le %le %le %le %le %le %le", scan->x1, scan->x2, scan->dJ, (scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2, scurve->parabstart, (scan->ds + scan2->ds)*mi / 2, fabs(scurve->parabstart)*(cmp*cmp) / 10, 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) - 2 * cmp*cmp2)*cmp);
3086
+ #endif
3087
+
3088
+ mi = fabs((parab1-parab2)*0.5) + fabs(scurve->parabstart)*(cmp_2 *0.1) + 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) - 2 * cmp*cmp2)*cmp;
3089
+ #ifdef _noparab
3090
+ mi = fabs(scurve->parabstart) * 2 + 0 * fabs((scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2 * cmp*cmp / 6);
3091
+ scurve->parabstart = 0.;
3092
+ #endif
3093
+
3094
+ #ifdef _selectimage
3095
+ if (_selectionimage)
3096
+ #endif
3097
+ pref=(scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) *0.5;
3098
+ theta->prev->Mag -= ((scan->dJ>0) ? -1 : 1)*(pref + scurve->parabstart);
3099
+ theta->prev->maxerr += mi;
3100
+
3101
+ #ifdef _ERRORS_ANALYTIC
3102
+ char filnam[32];
3103
+ sprintf(filnam, "%02dprev.txt", NPS);
3104
+ FILE* f = fopen(filnam, "a+");
3105
+ fprintf(f, "%.15le %.15le %.15le\n", -((scan->dJ > 0) ? -1 : 1)* (pref), -((scan->dJ > 0) ? -1 : 1)* (scurve->parabstart), mi);
3106
+ fclose(f);
3107
+ #endif
3108
+ scurve2->parabstart = -scurve->parabstart;
3109
+
3110
+ if(astrometry){
3111
+ dx2=scan2->x2 - scan->x2;
3112
+ avgx1=scan->x1 + scan2->x1;
3113
+ avg2x1=avgx1*avgx1;
3114
+ avgx2=scan->x2 + scan2->x2;
3115
+ theta->prev->astrox1 += ((scan->dJ>0) ? -1 : 1)*(avg2x1*dx2*0.125+scurve->parabastrox1);
3116
+ theta->prev->astrox2 -= ((scan->dJ>0) ? -1 : 1)*(pref*avgx2*0.25+scurve->parabastrox2);
3117
+ scurve2->parabastrox2=-scurve->parabastrox2;
3118
+ scurve2->parabastrox1=-scurve->parabastrox1;
3119
+ }
3120
+
3121
+
3122
+
3123
+ }
3124
+
3125
+ // Caso di distruzione immagini//
3126
+ if (nprec>npres) {
3127
+ mi = 1.e100;
3128
+ for (int i = 0; i<nprec - 1; i++) {
3129
+ for (int j = i + 1; j<nprec; j++) {
3130
+ cmp = *(cprec[i]->last) - *(cprec[j]->last);
3131
+ if (cmp<mi) {
3132
+ mi = cmp;
3133
+ issoc[0] = i;
3134
+ issoc[1] = j;
3135
+ }
3136
+ }
3137
+ }
3138
+ cprec[issoc[0]]->partneratend = cprec[issoc[1]];
3139
+ cprec[issoc[1]]->partneratend = cprec[issoc[0]];
3140
+
3141
+ scan = cprec[issoc[0]]->last;
3142
+ scan2 = cprec[issoc[1]]->last;
3143
+
3144
+ cmp2 = fabs(scan->d.re*scan2->d.re + scan->d.im*scan2->d.im);
3145
+ cmp = sqrt(mi / cmp2);
3146
+ cmp_2 = cmp*cmp;
3147
+ mi = cmp_2*cmp *0.04166666666667;
3148
+ parab1 = -(scan->ds - scan2->ds)*mi;
3149
+ parab2 = 0.0833333333 * ((scan2->x1 - scan->x1) * (scan2->d.im + scan->d.im) - (scan2->x2 - scan->x2) * (scan2->d.re + scan->d.re)) * cmp;
3150
+ scan->parab = 0.5 * (parab1 + parab2);
3151
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////astro: destructed image:
3152
+ if(astrometry){
3153
+ avgwedgex1=-(scan->x1*scan->ds - scan2->x1*scan2->ds)*mi;
3154
+ avgwedgex2=-(scan->x2*scan->ds - scan2->x2*scan2->ds)*mi;
3155
+ dx2=-(scan->d.im-scan2->d.im);
3156
+ d2x2=dx2*dx2;
3157
+ dx1=-(scan->d.re-scan2->d.re);
3158
+ d2x1=dx1*dx1;
3159
+ scan->parabastrox1 =-0.125*d2x1*dx2*mi-avgwedgex1;
3160
+ scan->parabastrox2 =-0.125*d2x2*dx1*mi+avgwedgex2;
3161
+
3162
+ }
3163
+ #ifdef _PRINT_ERRORS
3164
+ printf("\n%le %le %le %le %le %le %le %le", scan->x1, scan->x2, scan->dJ, (scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2, scan->parab, (scan->ds + scan2->ds)*mi / 2, fabs(scan->parab)*(cmp*cmp) / 10, 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) + 2 * cmp*cmp2)*cmp);
3165
+ #endif
3166
+
3167
+ mi = fabs((parab1-parab2)*0.5) + fabs(scan->parab)*(cmp*cmp *0.1) + 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) + 2.0 * cmp*cmp2)*cmp;
3168
+ #ifdef _noparab
3169
+ mi = fabs(scan->parab) * 2 + 0 * fabs((scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2 * cmp*cmp / 6);
3170
+ scan->parab = 0.;
3171
+ #endif
3172
+ #ifdef _selectimage
3173
+ if (_selectionimage)
3174
+ #endif
3175
+ pref=(scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) *0.5;
3176
+ theta->prev->Mag += ((scan->dJ>0) ? -1 : 1)*(pref+ scan->parab);
3177
+ #ifdef _ERRORS_ANALYTIC
3178
+ char filnam[32];
3179
+ sprintf(filnam, "%02dprev.txt", NPS);
3180
+ FILE* f = fopen(filnam, "a+");
3181
+ fprintf(f, "%.15le %.15le %.15le\n", ((scan->dJ > 0) ? -1 : 1)* (pref), ((scan->dJ > 0) ? -1 : 1)* (scan->parab), mi);
3182
+ fclose(f);
3183
+ #endif
3184
+ if(astrometry){
3185
+ dx2=scan2->x2 - scan->x2;
3186
+ avgx1=scan->x1 + scan2->x1;
3187
+ avg2x1=avgx1*avgx1;
3188
+ avgx2=scan->x2 + scan2->x2;
3189
+ theta->prev->astrox1 -= ((scan->dJ>0) ? -1 : 1)*(avg2x1*dx2*0.125+scan->parabastrox1);
3190
+ theta->prev->astrox2 += ((scan->dJ>0) ? -1 : 1)*(pref*avgx2*0.25+scan->parabastrox2);
3191
+ }
3192
+ theta->prev->maxerr += mi;
3193
+ scan2->parab = -scan->parab;
3194
+ if(astrometry){
3195
+ scan2->parabastrox2 =-scan->parabastrox2;
3196
+ scan2->parabastrox1 =-scan->parabastrox1;
3197
+ }
3198
+
3199
+
3200
+ nprec -= 2;
3201
+ ij = 0;
3202
+ for (int i = 0; i<nprec; i++) {
3203
+ if (i == issoc[0]) ij++;
3204
+ if (i == issoc[1] - 1) ij++;
3205
+ cprec[i] = cprec[i + ij];
3206
+ }
3207
+ }
3208
+
3209
+ // Costruzione matrice distanze con immagini precedenti//
3210
+ mi = 1.e100;
3211
+ for (int i = 0; i<nprec; i++) {
3212
+ cpres[i] = cprec[i];
3213
+ scan = Newpts->first;
3214
+ for (int j = 0; j<nprec; j++) {
3215
+ A[i][j] = (signbit(cprec[i]->last->dJ) == signbit(scan->dJ))? *(cprec[i]->last) - *scan : 100;
3216
+ if (A[i][j]<mi) {
3217
+ mi = A[i][j];
3218
+ issoc[0] = i;
3219
+ issoc[1] = j;
3220
+ isso[1] = scan;
3221
+ }
3222
+ scan = scan->next;
3223
+ }
3224
+ }
3225
+
3226
+ // Associazione con le immagini che precedono//
3227
+ while (nprec) {
3228
+ scan = cprec[issoc[0]]->last;
3229
+ scan2 = isso[1];
3230
+
3231
+ cmp2 = mi / fabs(scan->d.re*scan2->d.re + scan->d.im*scan2->d.im);
3232
+ cmp = (scan->theta->th - scan2->theta->th);
3233
+ cmp_2 = cmp*cmp;
3234
+ mi = cmp_2*cmp *0.0416666666666667; ////// (1/24 cube(delta Teta))
3235
+ parab1 = (scan->ds + scan2->ds)*mi; // Vecchia Correzione parabolica
3236
+ // Nuova correzione parabolica
3237
+ parab2 = 0.0833333333 * ((scan2->x1 - scan->x1) * (scan2->d.im - scan->d.im) - (scan2->x2 - scan->x2) * (scan2->d.re - scan->d.re)) * cmp;
3238
+ scan->parab = 0.5*(parab1+parab2);
3239
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////astro: ordinary image:
3240
+ if(astrometry){
3241
+ avgwedgex1=(scan->x1*scan->ds + scan2->x1*scan2->ds)*mi;
3242
+ avgwedgex2=(scan->x2*scan->ds + scan2->x2*scan2->ds)*mi;
3243
+ dx2=scan->d.im+scan2->d.im;
3244
+ d2x2=dx2*dx2;
3245
+ dx1=scan->d.re+scan2->d.re;
3246
+ d2x1=dx1*dx1;
3247
+ scan->parabastrox1 =-0.125*d2x1*dx2*mi-avgwedgex1;
3248
+ scan->parabastrox2 =-0.125*d2x2*dx1*mi+avgwedgex2;
3249
+ }
3250
+ #ifdef _PRINT_ERRORS
3251
+ printf("\n%le %le %le %le %le %le %le %le", scan->x1, scan->x2, scan->dJ, (scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2, scan->parab, (scan->ds - scan2->ds)*mi / 2, fabs(scan->parab)*(cmp2) / 10, fabs(scan->parab)*(1.5*fabs(cmp2 / (cmp*cmp) - 1)));
3252
+ #endif
3253
+
3254
+ mi = fabs((parab1 - parab2) *0.5) + fabs(scan->parab*(cmp2 *0.1 + 1.5*fabs(cmp2 / (cmp_2) - 1)));
3255
+ #ifdef _noparab
3256
+ mi = fabs(scan->parab) * 2 + 0 * fabs((scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2 * cmp*cmp / 6);
3257
+ scan->parab = 0.;
3258
+ #endif
3259
+ #ifdef _selectimage
3260
+ if (_selectionimage)
3261
+ #endif
3262
+ pref=(scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) *0.5;
3263
+ theta->prev->Mag += ((scan->dJ>0) ? -1 : 1)*( pref+ scan->parab);
3264
+ #ifdef _ERRORS_ANALYTIC
3265
+ char filnam[32];
3266
+ sprintf(filnam, "%02dprev.txt", NPS);
3267
+ FILE* f = fopen(filnam, "a+");
3268
+ fprintf(f, "%.15le %.15le %.15le\n", ((scan->dJ > 0) ? -1 : 1)* (pref), ((scan->dJ > 0) ? -1 : 1)* (scan->parab),mi);
3269
+ fclose(f);
3270
+ #endif
3271
+ if(astrometry){
3272
+ dx2=scan2->x2 - scan->x2;
3273
+ avgx1=scan->x1 + scan2->x1;
3274
+ avg2x1=avgx1*avgx1;
3275
+ avgx2=scan->x2 + scan2->x2;
3276
+ theta->prev->astrox1 -= ((scan->dJ>0) ? -1 : 1)*(avg2x1*dx2*0.125+scan->parabastrox1);
3277
+ theta->prev->astrox2 += ((scan->dJ>0) ? -1 : 1)*(pref*avgx2*0.25+scan->parabastrox2);
3278
+ }
3279
+ theta->prev->maxerr += mi;
3280
+
3281
+
3282
+
3283
+ Newpts->drop(isso[1]);
3284
+ cprec[issoc[0]]->append(isso[1]);
3285
+ cprec[issoc[0]]->partneratend = 0;
3286
+
3287
+ nprec--;
3288
+ for (int i = issoc[0]; i<nprec; i++) {
3289
+ cprec[i] = cprec[i + 1];
3290
+ for (int j = 0; j<nprec + 1; j++) {
3291
+ A[i][j] = A[i + 1][j];
3292
+ }
3293
+ }
3294
+ for (int j = issoc[1]; j<nprec; j++) {
3295
+ for (int i = 0; i<nprec; i++) {
3296
+ A[i][j] = A[i][j + 1];
3297
+ }
3298
+ }
3299
+ mi = 1.e100;
3300
+ for (int i = 0; i<nprec; i++) {
3301
+ scan = Newpts->first;
3302
+ for (int j = 0; j<nprec; j++) {
3303
+ if (A[i][j]<mi) {
3304
+ mi = A[i][j];
3305
+ issoc[0] = i;
3306
+ issoc[1] = j;
3307
+ isso[1] = scan;
3308
+ }
3309
+ scan = scan->next;
3310
+ }
3311
+ }
3312
+ }
3313
+ delete Newpts;
3314
+
3315
+ #ifdef _PRINT_ERRORS
3316
+ printf("\nN");
3317
+ #endif
3318
+
3319
+ // immagini seguenti//
3320
+ if (nfoll) {
3321
+ // Caso di creazione nuove immagini
3322
+
3323
+ if (npres<nfoll) {
3324
+ mi = 1.e100;
3325
+ for (int i = 0; i<nfoll - 1; i++) {
3326
+ for (int j = i + 1; j<nfoll; j++) {
3327
+ cmp = *(cfoll[i]->first) - *(cfoll[j]->first);
3328
+ if (cmp<mi) {
3329
+ mi = cmp;
3330
+ issoc[0] = i;
3331
+ issoc[1] = j;
3332
+ }
3333
+ }
3334
+ }
3335
+ cfoll[issoc[0]]->partneratstart = cfoll[issoc[1]];
3336
+ cfoll[issoc[1]]->partneratstart = cfoll[issoc[0]];
3337
+
3338
+ scan = cfoll[issoc[0]]->first;
3339
+ scan2 = cfoll[issoc[1]]->first;
3340
+
3341
+ cmp2 = fabs(scan->d.re*scan2->d.re + scan->d.im*scan2->d.im);
3342
+ cmp = sqrt(mi / cmp2);
3343
+ cmp_2 = cmp*cmp;
3344
+ mi = cmp_2*cmp *0.04166666666666667;
3345
+ parab1 = (scan->ds - scan2->ds)*mi;
3346
+ parab2 = -0.0833333333 * ((scan2->x1 - scan->x1) * (scan2->d.im + scan->d.im) - (scan2->x2 - scan->x2) * (scan2->d.re + scan->d.re)) * cmp;
3347
+ cfoll[issoc[0]]->parabstart = 0.5 * (parab1 + parab2);
3348
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////astro: created image:
3349
+ if(astrometry){
3350
+ avgwedgex1=(scan->x1*scan->ds - scan2->x1*scan2->ds)*mi;
3351
+ avgwedgex2=(scan->x2*scan->ds - scan2->x2*scan2->ds)*mi;
3352
+ dx2=-(-scan->d.im+scan2->d.im);
3353
+ d2x2=dx2*dx2;
3354
+ dx1=-(-scan->d.re+scan2->d.re);
3355
+ d2x1=dx1*dx1;
3356
+ cfoll[issoc[0]]->parabastrox1 =-0.125*d2x1*dx2*mi-avgwedgex1;
3357
+ cfoll[issoc[0]]->parabastrox2 =-0.125*d2x2*dx1*mi+avgwedgex2;
3358
+ }
3359
+ #ifdef _PRINT_ERRORS
3360
+ printf("\n%le %le %le %le %le %le %le %le", scan->x1, scan->x2, scan->dJ, (scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2, cfoll[issoc[0]]->parabstart, (scan->ds + scan2->ds)*mi / 2, fabs(cfoll[issoc[0]]->parabstart)*(cmp*cmp) / 10, 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) - 2 * cmp*cmp2)*cmp);
3361
+ #endif
3362
+ mi = fabs((parab1-parab2) *0.5) + fabs(cfoll[issoc[0]]->parabstart)*(cmp*cmp *0.1) + 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) - 2.0 * cmp*cmp2)*cmp;
3363
+ #ifdef _noparab
3364
+ mi = fabs(cfoll[issoc[0]]->parabstart) * 2 + 0 * fabs((scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2 * cmp*cmp / 6);
3365
+ cfoll[issoc[0]]->parabstart = 0.;
3366
+ #endif
3367
+ #ifdef _selectimage
3368
+ if (_selectionimage)
3369
+ #endif
3370
+ pref=(scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) *0.5;
3371
+ theta->Mag -= ((scan->dJ>0) ? -1 : 1)*(pref + cfoll[issoc[0]]->parabstart);
3372
+ #ifdef _ERRORS_ANALYTIC
3373
+ char filnam[32];
3374
+ sprintf(filnam, "%02dfoll.txt", NPS);
3375
+ FILE* f = fopen(filnam, "a+");
3376
+ fprintf(f, "%.15le %.15le %.15le\n", -((scan->dJ > 0) ? -1 : 1)* (pref), -((scan->dJ > 0) ? -1 : 1)* (cfoll[issoc[0]]->parabstart), mi);
3377
+ fclose(f);
3378
+ #endif
3379
+ if(astrometry){
3380
+ dx2=scan2->x2 - scan->x2;
3381
+ avgx1=scan->x1 + scan2->x1;
3382
+ avg2x1=avgx1*avgx1;
3383
+ avgx2=scan->x2 + scan2->x2;
3384
+ theta->astrox1 += ((scan->dJ>0) ? -1 : 1)*(avg2x1*dx2*0.125+cfoll[issoc[0]]->parabastrox1);
3385
+ theta->astrox2 -= ((scan->dJ>0) ? -1 : 1)*(pref*avgx2*0.25+cfoll[issoc[0]]->parabastrox2);
3386
+ }
3387
+ theta->maxerr += mi;
3388
+
3389
+ cfoll[issoc[1]]->parabstart = -cfoll[issoc[0]]->parabstart;
3390
+ if(astrometry){
3391
+ cfoll[issoc[1]]->parabastrox2=-cfoll[issoc[0]]->parabastrox2;
3392
+ cfoll[issoc[1]]->parabastrox1=-cfoll[issoc[0]]->parabastrox1;
3393
+ }
3394
+ Sols->append(cfoll[issoc[0]]);
3395
+ Sols->append(cfoll[issoc[1]]);
3396
+ nfoll -= 2;
3397
+ ij = 0;
3398
+ for (int i = 0; i<nfoll; i++) {
3399
+ if (i == issoc[0]) ij++;
3400
+ if (i == issoc[1] - 1) ij++;
3401
+ cfoll[i] = cfoll[i + ij];
3402
+ }
3403
+ }
3404
+
3405
+
3406
+ // Caso di distruzione immagini
3407
+ if (npres>nfoll) {
3408
+ mi = 1.e100;
3409
+ for (int i = 0; i<npres - 1; i++) {
3410
+ for (int j = i + 1; j<npres; j++) {
3411
+ cmp = *(cpres[i]->last) - *(cpres[j]->last);
3412
+ if (cmp<mi) {
3413
+ mi = cmp;
3414
+ issoc[0] = i;
3415
+ issoc[1] = j;
3416
+ }
3417
+ }
3418
+ }
3419
+ cpres[issoc[0]]->partneratend = cpres[issoc[1]];
3420
+ cpres[issoc[1]]->partneratend = cpres[issoc[0]];
3421
+
3422
+ scan = cpres[issoc[0]]->last;
3423
+ scan2 = cpres[issoc[1]]->last;
3424
+
3425
+ cmp2 = fabs(scan->d.re*scan2->d.re + scan->d.im*scan2->d.im);
3426
+ cmp = sqrt(mi / cmp2);
3427
+ cmp_2 = cmp*cmp;
3428
+ mi = cmp_2*cmp *0.0416666666667;
3429
+ parab1 = -(scan->ds - scan2->ds)*mi;
3430
+ parab2 = 0.0833333333 * ((scan2->x1 - scan->x1) * (scan2->d.im + scan->d.im) - (scan2->x2 - scan->x2) * (scan2->d.re + scan->d.re)) * cmp;
3431
+ scan->parab = 0.5 * (parab1 + parab2);
3432
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////astro: destructed image:
3433
+ if(astrometry){
3434
+ avgwedgex1=-(scan->x1*scan->ds - scan2->x1*scan2->ds)*mi;
3435
+ avgwedgex2=-(scan->x2*scan->ds - scan2->x2*scan2->ds)*mi;
3436
+ dx2=-(scan->d.im-scan2->d.im);
3437
+ d2x2=dx2*dx2;
3438
+ dx1=-(scan->d.re-scan2->d.re);
3439
+ d2x1=dx1*dx1;
3440
+ scan->parabastrox1 =-0.125*d2x1*dx2*mi-avgwedgex1;
3441
+ scan->parabastrox2 =-0.125*d2x2*dx1*mi+avgwedgex2;
3442
+ }
3443
+
3444
+ #ifdef _PRINT_ERRORS
3445
+ printf("\n%le %le %le %le %le %le %le %le", scan->x1, scan->x2, scan->dJ, (scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2, scan->parab, (scan->ds + scan2->ds)*mi / 2, fabs(scan->parab)*(cmp*cmp) / 10, 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) + 2 * cmp*cmp2)*cmp);
3446
+ #endif
3447
+
3448
+ mi = fabs((parab1-parab2) *0.5) + fabs(scan->parab)*(cmp*cmp *0.1) + 1.5*fabs(((scan->d.re - scan2->d.re)*(scan->x1 - scan2->x1) + (scan->d.im - scan2->d.im)*(scan->x2 - scan2->x2)) + 2.0 * cmp*cmp2)*cmp;
3449
+ #ifdef _noparab
3450
+ mi = fabs(scan->parab) * 2 + 0 * fabs((scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2 * cmp*cmp / 6);
3451
+ scan->parab = 0.;
3452
+ #endif
3453
+ #ifdef _selectimage
3454
+ if (_selectionimage)
3455
+ #endif
3456
+ pref=(scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) *0.5;
3457
+ theta->Mag += ((scan->dJ>0) ? -1 : 1)*( pref + scan->parab);
3458
+ #ifdef _ERRORS_ANALYTIC
3459
+ char filnam[32];
3460
+ sprintf(filnam, "%02dfoll.txt", NPS);
3461
+ FILE* f = fopen(filnam, "a+");
3462
+ fprintf(f, "%.15le %.15le %.15le\n", ((scan->dJ > 0) ? -1 : 1)* (pref), ((scan->dJ > 0) ? -1 : 1)* (scan->parab), mi);
3463
+ fclose(f);
3464
+ #endif
3465
+ if(astrometry){
3466
+ dx2=scan2->x2 - scan->x2;
3467
+ avgx1=scan->x1 + scan2->x1;
3468
+ avg2x1=avgx1*avgx1;
3469
+ avgx2=scan->x2 + scan2->x2;
3470
+ theta->astrox1 -= ((scan->dJ>0) ? -1 : 1)*(avg2x1*dx2*0.125+scan->parabastrox1);
3471
+ theta->astrox2 += ((scan->dJ>0) ? -1 : 1)*(pref*avgx2*0.25+scan->parabastrox2);
3472
+ }
3473
+ theta->maxerr += mi;
3474
+ scan2->parab = -scan->parab;
3475
+ if(astrometry){
3476
+ scan2->parabastrox2=-scan->parabastrox2;
3477
+ scan2->parabastrox1=-scan->parabastrox1;
3478
+ }
3479
+ npres -= 2;
3480
+ ij = 0;
3481
+ for (int i = 0; i<npres; i++) {
3482
+ if (i == issoc[0]) ij++;
3483
+ if (i == issoc[1] - 1) ij++;
3484
+ cpres[i] = cpres[i + ij];
3485
+ }
3486
+ }
3487
+
3488
+ // Costruzione matrice distanze con immagini seguenti
3489
+
3490
+ mi = 1.e100;
3491
+ for (int i = 0; i<npres; i++) {
3492
+ for (int j = 0; j<npres; j++) {
3493
+ A[i][j] = signbit(cpres[i]->last->dJ) == signbit(cfoll[j]->first->dJ)? *(cpres[i]->last) - *(cfoll[j]->first) : 100;
3494
+ if (A[i][j]<mi) {
3495
+ mi = A[i][j];
3496
+ issoc[0] = i;
3497
+ issoc[1] = j;
3498
+ }
3499
+ }
3500
+ }
3501
+
3502
+
3503
+ // Associazione con le immagini che seguono//
3504
+ while (npres) {
3505
+ scan = cpres[issoc[0]]->last;
3506
+ scan2 = cfoll[issoc[1]]->first;
3507
+ cmp2 = mi / fabs(scan->d.re*scan2->d.re + scan->d.im*scan2->d.im);
3508
+ cmp = (scan->theta->th - scan2->theta->th);
3509
+ cmp_2 = cmp*cmp;
3510
+ mi = cmp_2*cmp *0.041666666667;
3511
+ parab1 = (scan->ds + scan2->ds)*mi; // Vecchia Correzione parabolica
3512
+ // Nuova correzione parabolica
3513
+ parab2 = 0.0833333333 * ((scan2->x1 - scan->x1) * (scan2->d.im - scan->d.im) - (scan2->x2 - scan->x2) * (scan2->d.re - scan->d.re)) * cmp;
3514
+ scan->parab = 0.5*(parab1+parab2);
3515
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////astro: ordinary image:
3516
+ if(astrometry){
3517
+ avgwedgex1=(scan->x1*scan->ds + scan2->x1*scan2->ds)*mi;
3518
+ avgwedgex2=(scan->x2*scan->ds + scan2->x2*scan2->ds)*mi;
3519
+ dx2=scan->d.im+scan2->d.im;
3520
+ d2x2=dx2*dx2;
3521
+ dx1=scan->d.re+scan2->d.re;
3522
+ d2x1=dx1*dx1;
3523
+ scan->parabastrox1 =-0.125*d2x1*dx2*mi-avgwedgex1;
3524
+ scan->parabastrox2 =-0.125*d2x2*dx1*mi+avgwedgex2;
3525
+ }
3526
+
3527
+ #ifdef _PRINT_ERRORS
3528
+ printf("\n%le %le %le %le %le %le %le %le", scan->x1, scan->x2, scan->dJ, (scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2, scan->parab, (scan->ds - scan2->ds)*mi / 2, fabs(scan->parab)*(cmp2) / 10, fabs(scan->parab)*(1.5*fabs(cmp2 / (cmp*cmp) - 1)));
3529
+ #endif
3530
+
3531
+ mi = fabs((parab1-parab2) *0.5) + fabs(scan->parab*(cmp2 *0.1 + 1.5*fabs(cmp2 / (cmp_2) - 1)));
3532
+ #ifdef _noparab
3533
+ mi = fabs(scan->parab) * 2 + 0 * fabs((scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) / 2 * cmp*cmp / 6);
3534
+ scan->parab = 0.;
3535
+ #endif
3536
+ #ifdef _selectimage
3537
+ if (_selectionimage)
3538
+ #endif
3539
+ pref=(scan->x2 + scan2->x2)*(scan2->x1 - scan->x1) *0.5;
3540
+ theta->Mag += ((scan->dJ>0) ? -1 : 1)*(pref + scan->parab);
3541
+ if(astrometry){
3542
+ dx2=scan2->x2 - scan->x2;
3543
+ avgx1=scan->x1 + scan2->x1;
3544
+ avg2x1 = avgx1 * avgx1;
3545
+ avgx2=scan->x2 + scan2->x2;
3546
+ theta->astrox1 -= ((scan->dJ>0) ? -1 : 1)*(avg2x1*dx2*0.125+scan->parabastrox1);
3547
+ theta->astrox2 += ((scan->dJ>0) ? -1 : 1)*(pref*avgx2*0.25+scan->parabastrox2);
3548
+ }
3549
+ theta->maxerr += mi;
3550
+ #ifdef _ERRORS_ANALYTIC
3551
+ char filnam[32];
3552
+ sprintf(filnam, "%02dfoll.txt", NPS);
3553
+ FILE* f = fopen(filnam, "a+");
3554
+ fprintf(f, "%.15le %.15le %.15le\n", ((scan->dJ > 0) ? -1 : 1)* (pref), ((scan->dJ > 0) ? -1 : 1)* (scan->parab), mi);
3555
+ fclose(f);
3556
+ #endif
3557
+ cpres[issoc[0]]->join(cfoll[issoc[1]]);
3558
+
3559
+ npres--;
3560
+ for (int i = issoc[0]; i<npres; i++) {
3561
+ cpres[i] = cpres[i + 1];
3562
+ for (int j = 0; j<npres + 1; j++) {
3563
+ A[i][j] = A[i + 1][j];
3564
+ }
3565
+ }
3566
+ for (int j = issoc[1]; j<npres; j++) {
3567
+ cfoll[j] = cfoll[j + 1];
3568
+ for (int i = 0; i<npres; i++) {
3569
+ A[i][j] = A[i][j + 1];
3570
+ }
3571
+ }
3572
+ mi = 1.e100;
3573
+ for (int i = 0; i<npres; i++) {
3574
+ for (int j = 0; j<npres; j++) {
3575
+ if (A[i][j]<mi) {
3576
+ mi = A[i][j];
3577
+ issoc[0] = i;
3578
+ issoc[1] = j;
3579
+ }
3580
+ }
3581
+ }
3582
+ }
3583
+ }
3584
+
3585
+ }
3586
+
3587
+ //////////////////////////////
3588
+ //////////////////////////////
3589
+ ////////_point methods
3590
+ //////////////////////////////
3591
+ //////////////////////////////
3592
+
3593
+
3594
+ _point::_point(double x, double y, _theta *theta1) {
3595
+ x1 = x;
3596
+ x2 = y;
3597
+ theta = theta1;
3598
+ }
3599
+
3600
+ double _point::operator-(_point p2) {
3601
+ return (x1 - p2.x1)*(x1 - p2.x1) + (x2 - p2.x2)*(x2 - p2.x2);
3602
+ }
3603
+
3604
+ //////////////////////////////
3605
+ //////////////////////////////
3606
+ ////////_curve methods
3607
+ //////////////////////////////
3608
+ //////////////////////////////
3609
+
3610
+ _curve::_curve(void) {
3611
+ length = 0;
3612
+ first = last = 0;
3613
+ partneratstart = partneratend = 0;
3614
+ }
3615
+
3616
+ _curve::_curve(_point *p1) {
3617
+ length = 1;
3618
+ first = last = p1;
3619
+ p1->prev = p1->next = 0;
3620
+ partneratstart = partneratend = 0;
3621
+ }
3622
+
3623
+ _curve::~_curve(void) {
3624
+ _point *scan1, *scan2;
3625
+ scan1 = first;
3626
+ for (int i = 0; i<length; i++) {
3627
+ scan2 = scan1->next;
3628
+ delete scan1;
3629
+ scan1 = scan2;
3630
+ }
3631
+ }
3632
+
3633
+ _curve *_curve::divide(_point *ref) {
3634
+ _point *scan;
3635
+ _curve *nc;
3636
+ int l1;
3637
+
3638
+ l1 = 1;
3639
+ for (scan = first; scan != ref; scan = scan->next) l1++;
3640
+ nc = new _curve();
3641
+ nc->first = ref->next;
3642
+ nc->first->prev = 0;
3643
+ nc->last = last;
3644
+ nc->length = length - l1;
3645
+ nc->partneratend = partneratend;
3646
+ if (partneratend) partneratend->partneratend = nc;
3647
+
3648
+ length = l1;
3649
+ last = ref;
3650
+ ref->next = 0;
3651
+ partneratend = 0;
3652
+ return nc;
3653
+ }
3654
+
3655
+
3656
+ void _curve::append(double x1, double x2) {
3657
+ _point *pp;
3658
+ pp = new _point(x1, x2, 0);
3659
+ if (length == 0) {
3660
+ first = pp;
3661
+ last = pp;
3662
+ pp->prev = 0;
3663
+ }
3664
+ else {
3665
+ last->next = pp;
3666
+ pp->prev = last;
3667
+ last = pp;
3668
+ }
3669
+ pp->next = 0;
3670
+ length++;
3671
+ }
3672
+
3673
+ void _curve::append(_point *pp) {
3674
+
3675
+ pp->next = last->next;
3676
+ pp->prev = last;
3677
+ last->next = pp;
3678
+ last = pp;
3679
+ length++;
3680
+ }
3681
+
3682
+ void _curve::prepend(double x1, double x2) {
3683
+ _point *pp;
3684
+ pp = new _point(x1, x2, 0);
3685
+ if (length == 0) {
3686
+ first = pp;
3687
+ last = pp;
3688
+ pp->next = 0;
3689
+ }
3690
+ else {
3691
+ first->prev = pp;
3692
+ pp->next = first;
3693
+ first = pp;
3694
+ }
3695
+ pp->prev = 0;
3696
+ length++;
3697
+ }
3698
+
3699
+ _curve *_curve::join(_curve *nc) {
3700
+ if (length>0) {
3701
+ last->next = nc->first;
3702
+ }
3703
+ else {
3704
+ first = nc->first;
3705
+ };
3706
+ if (nc->length>0) {
3707
+ nc->first->prev = last;
3708
+ last = nc->last;
3709
+ }
3710
+ length += nc->length;
3711
+ partneratend = nc->partneratend;
3712
+ if (partneratend) partneratend->partneratend = this;
3713
+ nc->first = 0;
3714
+ nc->last = 0;
3715
+ nc->length = 0;
3716
+ delete nc;
3717
+ return this;
3718
+ }
3719
+
3720
+ _curve *_curve::joinbefore(_curve *nc) {
3721
+ if (length>0) {
3722
+ first->prev = nc->last;
3723
+ }
3724
+ else {
3725
+ last = nc->last;
3726
+ };
3727
+ if (nc->length>0) {
3728
+ nc->last->next = first;
3729
+ first = nc->first;
3730
+ }
3731
+ length += nc->length;
3732
+ nc->first = 0;
3733
+ nc->last = 0;
3734
+ nc->length = 0;
3735
+ delete nc;
3736
+ return this;
3737
+ }
3738
+
3739
+ _curve *_curve::reverse(void) {
3740
+ _point *scan1, *scan2, *scambio;
3741
+ if (length>1) {
3742
+ scan1 = first;
3743
+ while (scan1) {
3744
+ scan2 = scan1->next;
3745
+ scambio = scan1->next;
3746
+ scan1->next = scan1->prev;
3747
+ scan1->prev = scambio;
3748
+ scan1 = scan2;
3749
+ }
3750
+ scambio = first;
3751
+ first = last;
3752
+ last = scambio;
3753
+ }
3754
+ return this;
3755
+ }
3756
+
3757
+ void _curve::drop(_point *ref) {
3758
+ _point *scan;
3759
+ if (length) {
3760
+ for (scan = last; scan && (scan != ref); scan = scan->prev);
3761
+ if (scan) {
3762
+ if (length == 1) {
3763
+ first = last = 0;
3764
+ }
3765
+ else {
3766
+ if (ref->prev) {
3767
+ ref->prev->next = ref->next;
3768
+ if (ref == last) {
3769
+ last = ref->prev;
3770
+ }
3771
+ }
3772
+ if (ref->next) {
3773
+ ref->next->prev = ref->prev;
3774
+ if (ref == first) {
3775
+ first = ref->next;
3776
+ }
3777
+ }
3778
+ }
3779
+ length--;
3780
+ }
3781
+ }
3782
+ }
3783
+
3784
+ double _curve::closest2(_point *ref, _point **clos2) {
3785
+ double mi = 1.e100, mi2 = 1.e100, FP;
3786
+ _point *scan, *clos;
3787
+ if (length>1) {
3788
+ clos = *clos2 = first;
3789
+ for (scan = first; scan != 0; scan = scan->next) {
3790
+ FP = *scan - *ref;
3791
+ if (FP<mi) {
3792
+ mi2 = mi;
3793
+ mi = FP;
3794
+ *clos2 = clos;
3795
+ clos = scan;
3796
+ }
3797
+ else if (FP<mi2) {
3798
+ mi2 = FP;
3799
+ *clos2 = scan;
3800
+ }
3801
+ }
3802
+ }
3803
+ else {
3804
+ *clos2 = 0;
3805
+ }
3806
+ return (**clos2 - *ref);
3807
+ }
3808
+
3809
+ double _curve::closest(_point *ref, _point **clos) {
3810
+ double mi = 1.e100, FP;
3811
+ _point *scan;
3812
+ for (scan = first; scan != 0; scan = scan->next) {
3813
+ FP = *scan - *ref;
3814
+ if (FP<mi) {
3815
+ mi = FP;
3816
+ *clos = scan;
3817
+ }
3818
+ }
3819
+ return mi;
3820
+ }
3821
+
3822
+ void _curve::complement(_point **sott, int lensott, _point **res, int lenres) {
3823
+ int flag, i;
3824
+ _point *scan;
3825
+ i = 0;
3826
+ for (scan = first; scan != 0; scan = scan->next) {
3827
+ flag = 0;
3828
+ for (int j = 0; (j<lensott) && (!flag); j++) {
3829
+ if (scan == sott[j]) {
3830
+ flag = 1;
3831
+ }
3832
+ }
3833
+ if ((!flag) && (i<lenres)) {
3834
+ res[i] = scan;
3835
+ i++;
3836
+ }
3837
+ }
3838
+ }
3839
+
3840
+ //////////////////////////////
3841
+ //////////////////////////////
3842
+ ////////_sols methods
3843
+ //////////////////////////////
3844
+ //////////////////////////////
3845
+
3846
+
3847
+ _sols::_sols(void) {
3848
+ length = 0;
3849
+ first = last = 0;
3850
+ }
3851
+
3852
+ _sols::~_sols(void) {
3853
+ _curve *scan1, *scan2;
3854
+ scan1 = first;
3855
+ while (scan1) {
3856
+ scan2 = scan1->next;
3857
+ delete scan1;
3858
+ scan1 = scan2;
3859
+ }
3860
+ }
3861
+
3862
+ void _sols::append(_curve *cc) {
3863
+ if (length == 0) {
3864
+ first = cc;
3865
+ last = cc;
3866
+ cc->prev = 0;
3867
+ }
3868
+ else {
3869
+ last->next = cc;
3870
+ cc->prev = last;
3871
+ last = cc;
3872
+ }
3873
+ cc->next = 0;
3874
+ length++;
3875
+ }
3876
+
3877
+ void _sols::prepend(_curve *cc) {
3878
+ if (length == 0) {
3879
+ first = cc;
3880
+ last = cc;
3881
+ cc->next = 0;
3882
+ }
3883
+ else {
3884
+ first->prev = cc;
3885
+ cc->next = first;
3886
+ first = cc;
3887
+ }
3888
+ cc->prev = 0;
3889
+ length++;
3890
+ }
3891
+
3892
+ void _sols::drop(_curve *ref) {
3893
+ _curve *scan;
3894
+ if (length) {
3895
+ for (scan = last; scan && (scan != ref); scan = scan->prev);
3896
+ if (scan) {
3897
+ if (length == 1) {
3898
+ first = last = 0;
3899
+ }
3900
+ else {
3901
+ if (ref->prev) {
3902
+ ref->prev->next = ref->next;
3903
+ if (ref == last) {
3904
+ last = ref->prev;
3905
+ }
3906
+ }
3907
+ if (ref->next) {
3908
+ ref->next->prev = ref->prev;
3909
+ if (ref == first) {
3910
+ first = ref->next;
3911
+ }
3912
+ }
3913
+ }
3914
+ length--;
3915
+ }
3916
+ }
3917
+ }
3918
+
3919
+ void _sols::join(_sols *nc) {
3920
+ if (length>0) {
3921
+ last->next = nc->first;
3922
+ }
3923
+ else {
3924
+ first = nc->first;
3925
+ };
3926
+ if (nc->length>0) {
3927
+ nc->first->prev = last;
3928
+ last = nc->last;
3929
+ }
3930
+ length += nc->length;
3931
+ nc->first = 0;
3932
+ nc->last = 0;
3933
+ nc->length = 0;
3934
+ delete nc;
3935
+ }
3936
+
3937
+ //////////////////////////////
3938
+ //////////////////////////////
3939
+ ////////_theta methods
3940
+ //////////////////////////////
3941
+ //////////////////////////////
3942
+
3943
+ _theta::_theta(double th1) {
3944
+ th = th1;
3945
+ }
3946
+ _thetas::_thetas(void) {
3947
+ length = 0;
3948
+ }
3949
+
3950
+ _thetas::~_thetas(void) {
3951
+ _theta *scan, *scan2;
3952
+ scan = first;
3953
+ while (scan) {
3954
+ scan2 = scan->next;
3955
+ delete scan;
3956
+ scan = scan2;
3957
+ }
3958
+ }
3959
+
3960
+ _theta *_thetas::insert(double th) {
3961
+ _theta *scan, *scan2;
3962
+
3963
+ scan2 = new _theta(th);
3964
+ if (length) {
3965
+ if (th<first->th) {
3966
+ first->prev = scan2;
3967
+ scan2->next = first;
3968
+ scan2->prev = 0;
3969
+ first = scan2;
3970
+ }
3971
+ else {
3972
+ if (th>last->th) {
3973
+ last->next = scan2;
3974
+ scan2->prev = last;
3975
+ scan2->next = 0;
3976
+ last = scan2;
3977
+ }
3978
+ else {
3979
+ scan = first;
3980
+ while (scan->th<th) scan = scan->next;
3981
+ scan2->next = scan;
3982
+ scan2->prev = scan->prev;
3983
+ scan->prev->next = scan2;
3984
+ scan->prev = scan2;
3985
+ }
3986
+ }
3987
+ }
3988
+ else {
3989
+ first = scan2;
3990
+ last = scan2;
3991
+ scan2->next = 0;
3992
+ scan2->prev = 0;
3993
+ }
3994
+ length++;
3995
+ // scan2->maxerr=0.;
3996
+ return scan2;
3997
+ }
3998
+
3999
+ void _thetas::remove(_theta* stheta) {
4000
+ _theta *scan;
4001
+ scan = first;
4002
+ while (scan!=0) {
4003
+ if (scan == stheta) {
4004
+ if(scan!=first) scan->prev->next = stheta->next;
4005
+ if (scan != last) scan->next->prev = stheta->prev;
4006
+ delete stheta;
4007
+ length--;
4008
+ break;
4009
+ }
4010
+ scan = scan->next;
4011
+ }
4012
+ }
4013
+
4014
+ //////////////////////////////
4015
+ //////////////////////////////
4016
+ ////////complex methods and operators
4017
+ //////////////////////////////
4018
+ //////////////////////////////
4019
+
4020
+
4021
+ complex::complex(double a, double b) {
4022
+ re = a;
4023
+ im = b;
4024
+ }
4025
+
4026
+ complex::complex(double a) {
4027
+ re = a;
4028
+ im = 0;
4029
+ }
4030
+
4031
+ complex::complex(void) {
4032
+ re = 0;
4033
+ im = 0;
4034
+ }
4035
+
4036
+ double abs(complex z) {
4037
+ return sqrt(z.re*z.re + z.im*z.im);
4038
+ }
4039
+
4040
+ complex conj(complex z) {
4041
+ return complex(z.re, -z.im);
4042
+ }
4043
+
4044
+ complex sqrt(complex z) {
4045
+ double md = sqrt(z.re*z.re + z.im*z.im);
4046
+ return (md>0) ? complex((sqrt((md + z.re) / 2)*((z.im>0) ? 1 : -1)), sqrt((md - z.re) / 2)) : 0.0;
4047
+ }
4048
+
4049
+ double real(complex z) {
4050
+ return z.re;
4051
+ }
4052
+
4053
+ double imag(complex z) {
4054
+ return z.im;
4055
+ }
4056
+
4057
+ complex operator+(complex p1, complex p2) {
4058
+ return complex(p1.re + p2.re, p1.im + p2.im);
4059
+ }
4060
+
4061
+ complex operator-(complex p1, complex p2) {
4062
+ return complex(p1.re - p2.re, p1.im - p2.im);
4063
+ }
4064
+
4065
+ complex operator*(complex p1, complex p2) {
4066
+ return complex(p1.re*p2.re - p1.im*p2.im, p1.re*p2.im + p1.im*p2.re);
4067
+ }
4068
+
4069
+ complex operator/(complex p1, complex p2) {
4070
+ double md = p2.re*p2.re + p2.im*p2.im;
4071
+ return complex((p1.re*p2.re + p1.im*p2.im) / md, (p1.im*p2.re - p1.re*p2.im) / md);
4072
+ }
4073
+
4074
+ complex operator+(complex z, double a) {
4075
+ return complex(z.re + a, z.im);
4076
+ }
4077
+
4078
+ complex operator-(complex z, double a) {
4079
+ return complex(z.re - a, z.im);
4080
+ }
4081
+
4082
+ complex operator*(complex z, double a) {
4083
+ return complex(z.re*a, z.im*a);
4084
+ }
4085
+
4086
+ complex operator/(complex z, double a) {
4087
+ return complex(z.re / a, z.im / a);
4088
+ }
4089
+
4090
+ complex operator+(double a, complex z) {
4091
+ return complex(z.re + a, z.im);
4092
+ }
4093
+
4094
+ complex operator-(double a, complex z) {
4095
+ return complex(a - z.re, -z.im);
4096
+ }
4097
+
4098
+ complex operator*(double a, complex z) {
4099
+ return complex(a*z.re, a*z.im);
4100
+ }
4101
+
4102
+ complex operator/(double a, complex z) {
4103
+ double md = z.re*z.re + z.im*z.im;
4104
+ return complex(a*z.re / md, -a*z.im / md);
4105
+ }
4106
+
4107
+
4108
+ complex operator+(complex z, int a) {
4109
+ return complex(z.re + a, z.im);
4110
+ }
4111
+
4112
+ complex operator-(complex z, int a) {
4113
+ return complex(z.re - a, z.im);
4114
+ }
4115
+
4116
+ complex operator*(complex z, int a) {
4117
+ return complex(z.re*a, z.im*a);
4118
+ }
4119
+
4120
+ complex operator/(complex z, int a) {
4121
+ return complex(z.re / a, z.im / a);
4122
+ }
4123
+
4124
+ complex operator+(int a, complex z) {
4125
+ return complex(z.re + a, z.im);
4126
+ }
4127
+
4128
+ complex operator-(int a, complex z) {
4129
+ return complex(a - z.re, -z.im);
4130
+ }
4131
+
4132
+ complex operator*(int a, complex z) {
4133
+ return complex(a*z.re, a*z.im);
4134
+ }
4135
+
4136
+ complex operator/(int a, complex z) {
4137
+ double md = z.re*z.re + z.im*z.im;
4138
+ return complex(a*z.re / md, -a*z.im / md);
4139
+ }
4140
+
4141
+ complex operator-(complex z) {
4142
+ return complex(-z.re, -z.im);
4143
+ }
4144
+
4145
+ bool operator==(complex p1, complex p2) {
4146
+ if (p1.re == p2.re && p1.im == p2.im) return true;
4147
+ return false;
4148
+ }
4149
+
4150
+ bool operator!=(complex p1, complex p2) {
4151
+ if (p1.re == p2.re && p1.im == p2.im) return false;
4152
+ return true;
4153
+ }
4154
+
4155
+ complex expcmplx(complex p1) {
4156
+ double r = exp(p1.re);
4157
+ double theta = atan2(p1.im, p1.re);
4158
+ return complex(r*cos(theta), r*sin(theta));
4159
+ }
4160
+
4161
+ complex cbrt(complex z) {
4162
+ complex zout;
4163
+ double r, r_cube, theta, theta_cube;
4164
+ r = abs(z);
4165
+ r_cube = pow(r, 0.333333333333);
4166
+ theta = atan2(z.im, z.re);
4167
+ theta_cube = theta / 3.;
4168
+ return complex(r_cube*cos(theta_cube), r_cube*sin(theta_cube));
4169
+ }
4170
+
4171
+ //////////////////////////////
4172
+ //////////////////////////////
4173
+ ////////_Skowron & Gould functions, translated by Tyler M. Heintz and Ava R. Hoag
4174
+ //////////////////////////////
4175
+ //////////////////////////////
4176
+ // See copyright notice for these functions
4177
+
4178
+
4179
+ void VBBinaryLensing::cmplx_roots_gen(complex *roots, complex *poly, int degree, bool polish_roots_after, bool use_roots_as_starting_points) {
4180
+ //roots - array which will hold all roots that had been found.
4181
+ //If the flag 'use_roots_as_starting_points' is set to
4182
+ //.true., then instead of point(0, 0) we use value from
4183
+ //this array as starting point for cmplx_laguerre
4184
+
4185
+ //poly - is an array of polynomial cooefs, length = degree + 1,
4186
+ //poly[0] x ^ 0 + poly[1] x ^ 1 + poly[2] x ^ 2 + ...
4187
+
4188
+ //degree - degree of the polynomial and size of 'roots' array
4189
+
4190
+ //polish_roots_after - after all roots have been found by dividing
4191
+ //original polynomial by each root found,
4192
+ //you can opt in to polish all roots using full
4193
+ //polynomial
4194
+
4195
+ //use_roots_as_starting_points - usually we start Laguerre's
4196
+ //method from point(0, 0), but you can decide to use the
4197
+ //values of 'roots' array as starting point for each new
4198
+ //root that is searched for.This is useful if you have
4199
+ //very rough idea where some of the roots can be.
4200
+ //
4201
+
4202
+ complex poly2[MAXM];
4203
+ static int i, j, n, iter;
4204
+ bool success;
4205
+ complex coef, prev;
4206
+
4207
+ if (!use_roots_as_starting_points) {
4208
+ for (int jj = 0; jj < degree; jj++) {
4209
+ roots[jj] = complex(0, 0);
4210
+ }
4211
+ }
4212
+
4213
+ for (j = 0; j <= degree; j++) poly2[j] = poly[j];
4214
+
4215
+ // Don't do Laguerre's for small degree polynomials
4216
+ if (degree <= 1) {
4217
+ if (degree == 1) roots[0] = -poly[0] / poly[1];
4218
+ return;
4219
+ }
4220
+
4221
+ for (n = degree; n >= 3; n--) {
4222
+ cmplx_laguerre2newton(poly2, n, &roots[n - 1], iter, success, 2);
4223
+ if (!success) {
4224
+ roots[n - 1] = complex(0, 0);
4225
+ cmplx_laguerre(poly2, n, &roots[n - 1], iter, success);
4226
+ }
4227
+
4228
+ // Divide by root
4229
+ coef = poly2[n];
4230
+ for (i = n - 1; i >= 0; i--) {
4231
+ prev = poly2[i];
4232
+ poly2[i] = coef;
4233
+ coef = prev + roots[n - 1] * coef;
4234
+ }
4235
+ }
4236
+
4237
+
4238
+ //Find the to last 2 roots
4239
+ solve_quadratic_eq(roots[1], roots[0], poly2);
4240
+ //cmplx_laguerre2newton(poly2, 2, &roots[1], iter, success, 2);
4241
+ //if (!success) {
4242
+ // solve_quadratic_eq(roots[1], roots[0], poly2);
4243
+ //}
4244
+ //else {
4245
+ // roots[0] = -(roots[1] + poly2[1] / poly2[2]); // Viete's Formula for the last root
4246
+ //}
4247
+
4248
+
4249
+
4250
+ if (polish_roots_after) {
4251
+ for (n = 0; n < degree; n++) {
4252
+ cmplx_newton_spec(poly, degree, &roots[n], iter, success); // Polish roots with full polynomial
4253
+ }
4254
+ }
4255
+
4256
+ return;
4257
+ }
4258
+
4259
+ void VBBinaryLensing::solve_quadratic_eq(complex &x0, complex &x1, complex *poly) {
4260
+ complex a, b, c, b2, delta;
4261
+ a = poly[2];
4262
+ b = poly[1];
4263
+ c = poly[0];
4264
+ b2 = b*b;
4265
+ delta = sqrt(b2 - 4 * a*c);
4266
+ if (real(conj(b)*delta) >= 0) {
4267
+ x0 = -0.5*(b + delta);
4268
+ }
4269
+ else {
4270
+ x0 = -0.5*(b - delta);
4271
+ }
4272
+ if (x0 == complex(0., 0.)) {
4273
+ x1 = complex(0., 0.);
4274
+ }
4275
+ else { //Viete's formula
4276
+ x1 = c / x0;
4277
+ x0 = x0 / a;
4278
+ }
4279
+ return;
4280
+
4281
+ }
4282
+
4283
+ void VBBinaryLensing::solve_cubic_eq(complex &x0, complex &x1, complex &x2, complex *poly) {
4284
+ //Cubic equation solver for comples polynomial (degree=3)
4285
+ //http://en.wikipedia.org/wiki/Cubic_function Lagrange's method
4286
+ // poly is an array of polynomial cooefs, length = degree+1, poly[0] is constant
4287
+ // 0 1 2 3
4288
+ //poly[0] x^0 + poly[1] x^1 + poly[2] x^2 + poly[3] x^3
4289
+ complex zeta = complex(-0.5, 0.8660254037844386);
4290
+ complex zeta2 = complex(-0.5, -0.8660254037844386);
4291
+ double third = 0.3333333333333333;
4292
+ complex s0, s1, s2;
4293
+ complex E1; //x0+x1+x2
4294
+ complex E2; //x0*x1+x1*x2+x2*x0
4295
+ complex E3; //x0*x1*x2
4296
+ complex A, B, a_1, E12, delta, A2;
4297
+
4298
+ complex val, x;
4299
+ a_1 = 1 / poly[3];
4300
+ E1 = -poly[2] * a_1;
4301
+ E2 = poly[1] * a_1;
4302
+ E3 = -poly[0] * a_1;
4303
+
4304
+ s0 = E1;
4305
+ E12 = E1*E1;
4306
+ A = 2.0 * E1 * E12 - 9.0 * E1 * E2 + 27.0 * E3;
4307
+ B = E12 - 3.0 * E2;
4308
+ //quadratic equation z^2 - A * z + B^3 where roots are equal to s1^3 and s2^3
4309
+ A2 = A * A;
4310
+ delta = sqrt(A2 - 4.0 * (B * B * B));
4311
+ if (real(conj(A) * delta) >= 0.0) { // scalar product to decide the sign yielding bigger magnitude
4312
+ s1 = cbrt(0.5 * (A + delta));
4313
+ }
4314
+ else
4315
+ {
4316
+ s1 = cbrt(0.5 * (A - delta));
4317
+ }
4318
+ if (s1.re == 0.0 && s1.im == 0.0) {
4319
+ s2 = complex(0, 0);
4320
+ }
4321
+ else {
4322
+ s2 = B / s1;
4323
+ }
4324
+
4325
+ x0 = third * (s0 + s1 + s2);
4326
+ x1 = third * (s0 + s1 * zeta2 + s2 * zeta);
4327
+ x2 = third * (s0 + s1 * zeta + s2 * zeta2);
4328
+
4329
+ return;
4330
+
4331
+ }
4332
+
4333
+ void VBBinaryLensing::cmplx_laguerre(complex *poly, int degree, complex *root, int &iter, bool &success) {
4334
+ //Subroutine finds one root of a complex polynomial using
4335
+ //Laguerre's method. In every loop it calculates simplified
4336
+ //Adams' stopping criterion for the value of the polynomial.
4337
+ //
4338
+ //Uses 'root' value as a starting point(!!!!!)
4339
+ //Remember to initialize 'root' to some initial guess or to
4340
+ //point(0, 0) if you have no prior knowledge.
4341
+ //
4342
+ //poly - is an array of polynomial cooefs
4343
+ //
4344
+ //length = degree + 1, poly(1) is constant
4345
+ // 1 2 3
4346
+ //poly(1) x ^ 0 + poly(2) x ^ 1 + poly(3) x ^ 2 + ...
4347
+ //
4348
+ //degree - a degree of the polynomial
4349
+ //
4350
+ //root - input: guess for the value of a root
4351
+ //output : a root of the polynomial
4352
+ //iter - number of iterations performed(the number of polynomial
4353
+ //evaluations and stopping criterion evaluation)
4354
+ //
4355
+ //success - is false if routine reaches maximum number of iterations
4356
+ //
4357
+ //For a summary of the method go to :
4358
+ //http://en.wikipedia.org/wiki/Laguerre's_method
4359
+ //
4360
+ static int FRAC_JUMP_EVERY = 10;
4361
+ const int FRAC_JUMP_LEN = 10;
4362
+ double FRAC_JUMPS[FRAC_JUMP_LEN] = { 0.64109297,
4363
+ 0.91577881, 0.25921289, 0.50487203,
4364
+ 0.08177045, 0.13653241, 0.306162,
4365
+ 0.37794326, 0.04618805, 0.75132137 }; // some random numbers
4366
+
4367
+ double faq; //jump length
4368
+ double FRAC_ERR = 2.0e-15; //Fractional Error for double precision
4369
+ complex p, dp, d2p_half; //value of polynomial, 1st derivative, and 2nd derivative
4370
+ static int i, j, k;
4371
+ bool good_to_go;
4372
+ complex denom, denom_sqrt, dx, newroot;
4373
+ double ek, absroot, abs2p;
4374
+ complex fac_newton, fac_extra, F_half, c_one_nth;
4375
+ double one_nth, n_1_nth, two_n_div_n_1;
4376
+ complex c_one = complex(1, 0);
4377
+ complex zero = complex(0, 0);
4378
+ double stopping_crit2;
4379
+
4380
+ //--------------------------------------------------------------------------------------------
4381
+
4382
+ //EXTREME FAILSAFE! not usually needed but kept here just to be on the safe side. Takes care of first coefficient being 0
4383
+ if (false) {
4384
+ if (degree < 0) {
4385
+ printf("Error: cmplx_laguerre: degree<0");
4386
+ return;
4387
+ }
4388
+ if (poly[degree] == complex(0, 0)) {
4389
+ if (degree == 0) return;
4390
+ cmplx_laguerre(poly, degree - 1, root, iter, success);
4391
+ }
4392
+ if (degree <= 1) {
4393
+ if (degree == 0) {
4394
+ success = false; // we just checked if poly[0] is zero and it isnt
4395
+ printf("Warning: cmplx_laguerre: degree = 0 and poly[0] does not equal zero, no roots");
4396
+ return;
4397
+ }
4398
+ else {
4399
+ *root = -poly[0] / poly[1];
4400
+ return;
4401
+ }
4402
+ }
4403
+ } // End of EXTREME failsafe
4404
+
4405
+ good_to_go = false;
4406
+ one_nth = 1.0 / degree;
4407
+ n_1_nth = (degree - 1.0)*one_nth;
4408
+ two_n_div_n_1 = 2.0 / n_1_nth;
4409
+ c_one_nth = complex(one_nth, 0.0);
4410
+ for (i = 1; i <= MAXIT; i++) {
4411
+ ek = abs(poly[degree]); // Preparing stopping criterion
4412
+ absroot = abs(*root);
4413
+ // Calculate the values of polynomial and its first and second derivatives
4414
+ p = poly[degree];
4415
+ dp = zero;
4416
+ d2p_half = zero;
4417
+ for (k = degree - 1; k >= 0; k--) {
4418
+ d2p_half = dp + d2p_half*(*root);
4419
+ dp = p + dp * *root;
4420
+ p = poly[k] + p*(*root); // b_k
4421
+ //Adams, Duane A., 1967, "A stopping criterion for polynomial root finding",
4422
+ //Communications of the ACM, Volume 10 Issue 10, Oct. 1967, p. 655
4423
+ //ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/67/55/CS-TR-67-55.pdf
4424
+ //Eq 8.
4425
+ ek = absroot*ek + abs(p);
4426
+ }
4427
+ iter += 1;
4428
+
4429
+ abs2p = real(conj(p)*p);
4430
+ if (abs2p == 0) return;
4431
+ stopping_crit2 = pow(FRAC_ERR*ek, 2.0);
4432
+ if (abs2p < stopping_crit2) {
4433
+ //(simplified a little Eq. 10 of Adams 1967)
4434
+ //do additional iteration if we are less than 10x from stopping criterion
4435
+ if (abs2p < 0.01*stopping_crit2) {
4436
+ return; // we are at a good place!
4437
+ }
4438
+ else {
4439
+ good_to_go = true;
4440
+ }
4441
+ }
4442
+ else {
4443
+ good_to_go = false;
4444
+ }
4445
+
4446
+ faq = 1.0;
4447
+ denom = zero;
4448
+ if (dp != zero) {
4449
+ fac_newton = p / dp;
4450
+ fac_extra = d2p_half / dp;
4451
+ F_half = fac_newton*fac_extra;
4452
+ denom_sqrt = sqrt(c_one - two_n_div_n_1*F_half);
4453
+
4454
+ //NEXT LINE PROBABLY CAN BE COMMENTED OUT. Check if compiler outputs positive real
4455
+ if (real(denom_sqrt) >= 0.0) {
4456
+ denom = c_one_nth + n_1_nth*denom_sqrt;
4457
+ }
4458
+ else {
4459
+ denom = c_one_nth - n_1_nth*denom_sqrt;
4460
+ }
4461
+ }
4462
+
4463
+ if (denom == 0) {
4464
+ dx = (absroot + 1.0)*expcmplx(complex(0.0, FRAC_JUMPS[i % FRAC_JUMP_LEN] * 2 * M_PI));
4465
+ }
4466
+ else {
4467
+ dx = fac_newton / denom;
4468
+ }
4469
+
4470
+
4471
+ newroot = *root - dx;
4472
+ if (newroot == *root) return; //nothing changes so return
4473
+ if (good_to_go) {
4474
+ *root = newroot;
4475
+ return;
4476
+ }
4477
+ if (i % FRAC_JUMP_EVERY == 0) { //decide whether to do a jump of modified length (to break cycles)
4478
+ faq = FRAC_JUMPS[(i / FRAC_JUMP_EVERY - 1) % FRAC_JUMP_LEN];
4479
+ newroot = *root - faq*dx; // do jump of semi-random length
4480
+ }
4481
+ *root = newroot;
4482
+ }
4483
+ success = false; // too many iterations here
4484
+ return;
4485
+ }
4486
+
4487
+ void VBBinaryLensing::cmplx_newton_spec(complex *poly, int degree, complex *root, int &iter, bool &success) {
4488
+ //Subroutine finds one root of a complex polynomial
4489
+ //Newton's method. It calculates simplified Adams' stopping
4490
+ //criterion for the value of the polynomial once per 10 iterations (!),
4491
+ //after initial iteration. This is done to speed up calculations
4492
+ //when polishing roots that are known preety well, and stopping
4493
+ // criterion does significantly change in their neighborhood.
4494
+
4495
+ //Uses 'root' value as a starting point (!!!!!)
4496
+ //Remember to initialize 'root' to some initial guess.
4497
+ //Do not initilize 'root' to point (0,0) if the polynomial
4498
+ //coefficients are strictly real, because it will make going
4499
+ //to imaginary roots impossible.
4500
+
4501
+ // poly - is an array of polynomial cooefs
4502
+ // length = degree+1, poly(1) is constant
4503
+ //0 1 2
4504
+ //poly[0] x^0 + poly[1] x^1 + poly[2] x^2 + ...
4505
+ //degree - a degree of the polynomial
4506
+ // root - input: guess for the value of a root
4507
+ // output: a root of the polynomial
4508
+ //iter - number of iterations performed (the number of polynomial evaluations)
4509
+ //success - is false if routine reaches maximum number of iterations
4510
+
4511
+ //For a summary of the method go to:
4512
+ //http://en.wikipedia.org/wiki/Newton's_method
4513
+
4514
+ int FRAC_JUMP_EVERY = 10;
4515
+ const int FRAC_JUMP_LEN = 10;
4516
+ double FRAC_JUMPS[FRAC_JUMP_LEN] = { 0.64109297, 0.91577881, 0.25921289, 0.50487203, 0.08177045, 0.13653241, 0.306162, 0.37794326, 0.04618805, 0.75132137 }; //some random numbers
4517
+ double faq; //jump length
4518
+ double FRAC_ERR = 2e-15;
4519
+ complex p; //value of polynomial
4520
+ complex dp; //value of 1st derivative
4521
+ int i, k;
4522
+ bool good_to_go;
4523
+ complex dx, newroot;
4524
+ double ek, absroot, abs2p;
4525
+ complex zero = complex(0, 0);
4526
+ double stopping_crit2;
4527
+
4528
+ iter = 0;
4529
+ success = true;
4530
+
4531
+ //the next if block is an EXTREME failsafe, not usually needed, and thus turned off in this version
4532
+ if (false) { //change false to true if you would like to use caustion about haveing first coefficient == 0
4533
+ if (degree < 0) {
4534
+ printf("Error: cmplx_newton_spec: degree<0");
4535
+ return;
4536
+ }
4537
+ if (poly[degree] == zero) {
4538
+ if (degree == 0) return;
4539
+ cmplx_newton_spec(poly, degree, root, iter, success);
4540
+ return;
4541
+ }
4542
+ if (degree <= 1) {
4543
+ if (degree == 0) {
4544
+ success = false;
4545
+ printf("Warning: cmplx_newton_spec: degree=0 and poly[0]!=0, no roots");
4546
+ return;
4547
+ }
4548
+ else {
4549
+ *root = -poly[0] / poly[1];
4550
+ return;
4551
+ }
4552
+ }
4553
+ }
4554
+ //end EXTREME Failsafe
4555
+ good_to_go = false;
4556
+
4557
+ stopping_crit2 = 0.0; //value not important, will be initialized anyway on the first loop
4558
+ for (i = 1; i <= MAXIT; i++) {
4559
+ faq = 1.0;
4560
+ //prepare stoping criterion
4561
+ //calculate value of polynomial and its first two derivatives
4562
+ p = poly[degree];
4563
+ dp = zero;
4564
+ if (i % 10 == 1) { //calculate stopping criterion every tenth iteration
4565
+ ek = abs(poly[degree]);
4566
+ absroot = abs(*root);
4567
+ for (k = degree - 1; k >= 0; k--) {
4568
+ dp = p + dp * (*root);
4569
+ p = poly[k] + p * (*root); //b_k
4570
+ //Adams, Duane A., 1967, "A stopping criterion for polynomial root finding",
4571
+ //Communications of ACM, Volume 10 Issue 10, Oct. 1967, p. 655
4572
+ //ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/67/55/CS-TR-67-55.pdf
4573
+ //Eq. 8
4574
+ ek = absroot * ek + abs(p);
4575
+ }
4576
+ stopping_crit2 = pow(FRAC_ERR * ek, 2);
4577
+ }
4578
+ else { // calculate just the value and derivative
4579
+ for (k = degree - 1; k >= 0; k--) { //Horner Scheme, see for eg. Numerical Recipes Sec. 5.3 how to evaluate polynomials and derivatives
4580
+ dp = p + dp * (*root);
4581
+ p = poly[k] + p * (*root);
4582
+ }
4583
+ }
4584
+
4585
+ iter = iter + 1;
4586
+
4587
+ abs2p = real(conj(p) * p);
4588
+ if (abs2p == 0.0) return;
4589
+ if (abs2p < stopping_crit2) { //simplified a little Eq. 10 of Adams 1967
4590
+ if (dp == zero) return; //if we have problem with zero, but we are close to the root, just accept
4591
+ //do additional iteration if we are less than 10x from stopping criterion
4592
+ if (abs2p < 0.01 * stopping_crit2) return; //return immediatley because we are at very good place
4593
+ else {
4594
+ good_to_go = true; //do one iteration more
4595
+ }
4596
+ }
4597
+
4598
+ else {
4599
+ good_to_go = false; //reset if we are outside the zone of the root
4600
+ }
4601
+ if (dp == zero) {
4602
+ //problem with zero
4603
+ dx = (abs(*root) + 1.0) * expcmplx(complex(0.0, FRAC_JUMPS[i% FRAC_JUMP_LEN] * 2 * M_PI));
4604
+ }
4605
+ else {
4606
+ dx = p / dp; // Newton method, see http://en.wikipedia.org/wiki/Newton's_method
4607
+ }
4608
+ newroot = *root - dx;
4609
+ if (newroot == *root) return; //nothing changes -> return
4610
+ if (good_to_go) {//this was jump already after stopping criterion was met
4611
+ *root = newroot;
4612
+ return;
4613
+ }
4614
+ if (i % FRAC_JUMP_EVERY == 0) { // decide whether to do a jump of modified length (to break cycles)
4615
+ faq = FRAC_JUMPS[(i / FRAC_JUMP_EVERY - 1) % FRAC_JUMP_LEN];
4616
+ newroot = *root - faq * dx;
4617
+ }
4618
+ *root = newroot;
4619
+ }
4620
+ success = false;
4621
+ return;
4622
+ //too many iterations here
4623
+ }
4624
+
4625
+ void VBBinaryLensing::cmplx_laguerre2newton(complex *poly, int degree, complex *root, int &iter, bool &success, int starting_mode) {
4626
+ //Subroutine finds one root of a complex polynomial using
4627
+ //Laguerre's method, Second-order General method and Newton's
4628
+ //method - depending on the value of function F, which is a
4629
+ //combination of second derivative, first derivative and
4630
+ //value of polynomial [F=-(p"*p)/(p'p')].
4631
+
4632
+ //Subroutine has 3 modes of operation. It starts with mode=2
4633
+ //which is the Laguerre's method, and continues until F
4634
+ //becames F<0.50, at which point, it switches to mode=1,
4635
+ //i.e., SG method (see paper). While in the first two
4636
+ //modes, routine calculates stopping criterion once per every
4637
+ //iteration. Switch to the last mode, Newton's method, (mode=0)
4638
+ //happens when becomes F<0.05. In this mode, routine calculates
4639
+ //stopping criterion only once, at the beginning, under an
4640
+ //assumption that we are already very close to the root.
4641
+ //If there are more than 10 iterations in Newton's mode,
4642
+ //it means that in fact we were far from the root, and
4643
+ //routine goes back to Laguerre's method (mode=2).
4644
+
4645
+ //Uses 'root' value as a starting point (!!!!!)
4646
+ //Remember to initialize 'root' to some initial guess or to
4647
+ //point (0,0) if you have no prior knowledge.
4648
+
4649
+ //poly - is an array of polynomial cooefs
4650
+ // 0 1 2
4651
+ // poly[0] x^0 + poly[1] x^1 + poly[2] x^2
4652
+ //degree - a degree of the polynomial
4653
+ //root - input: guess for the value of a root
4654
+ // output: a root of the polynomial
4655
+ //iter - number of iterations performed (the number of polynomial
4656
+ // evaluations and stopping criterion evaluation)
4657
+ //success - is false if routine reaches maximum number of iterations
4658
+ //starting_mode - this should be by default = 2. However if you
4659
+ // choose to start with SG method put 1 instead.
4660
+ // Zero will cause the routine to
4661
+ // start with Newton for first 10 iterations, and
4662
+ // then go back to mode 2.
4663
+
4664
+ //For a summary of the method see the paper: Skowron & Gould (2012)
4665
+
4666
+ int FRAC_JUMP_EVERY = 10;
4667
+ const int FRAC_JUMP_LEN = 10;
4668
+ double FRAC_JUMPS[FRAC_JUMP_LEN] = { 0.64109297, 0.91577881, 0.25921289, 0.50487203, 0.08177045, 0.13653241, 0.306162, 0.37794326, 0.04618805, 0.75132137 }; //some random numbers
4669
+
4670
+ double faq; //jump length
4671
+ double FRAC_ERR = 2.0e-15;
4672
+
4673
+ complex p; //value of polynomial
4674
+ complex dp; //value of 1st derivative
4675
+ complex d2p_half; //value of 2nd derivative
4676
+ int i, j, k;
4677
+ bool good_to_go;
4678
+ //complex G, H, G2;
4679
+ complex denom, denom_sqrt, dx, newroot;
4680
+ double ek, absroot, abs2p, abs2_F_half;
4681
+ complex fac_netwon, fac_extra, F_half, c_one_nth;
4682
+ double one_nth, n_1_nth, two_n_div_n_1;
4683
+ int mode;
4684
+ complex c_one = complex(1, 0);
4685
+ complex zero = complex(0, 0);
4686
+ double stopping_crit2;
4687
+
4688
+ iter = 0;
4689
+ success = true;
4690
+ stopping_crit2 = 0; //value not important, will be initialized anyway on the first loop
4691
+
4692
+ //next if block is an EXTREME failsafe, not usually needed, and thus turned off in this version.
4693
+ if (false) {//change false to true if you would like to use caution about having first coefficent == 0
4694
+ if (degree < 0) {
4695
+ printf("Error: cmplx_laguerre2newton: degree < 0");
4696
+ return;
4697
+ }
4698
+ if (poly[degree] == zero) {
4699
+ if (degree == 0) return;
4700
+ cmplx_laguerre2newton(poly, degree, root, iter, success, starting_mode);
4701
+ return;
4702
+ }
4703
+ if (degree <= 1) {
4704
+ if (degree == 0) {//// we know from previous check that poly[0] not equal zero
4705
+ success = false;
4706
+ printf("Warning: cmplx_laguerre2newton: degree = 0 and poly[0] = 0, no roots");
4707
+ return;
4708
+ }
4709
+ else {
4710
+ *root = -poly[0] / poly[1];
4711
+ return;
4712
+ }
4713
+ }
4714
+ }
4715
+ //end EXTREME failsafe
4716
+
4717
+ j = 1;
4718
+ good_to_go = false;
4719
+
4720
+ mode = starting_mode; // mode = 2 full laguerre, mode = 1 SG, mode = 0 newton
4721
+
4722
+ for (;;) { //infinite loop, just to be able to come back from newton, if more than 10 iteration there
4723
+
4724
+ ////////////
4725
+ ///mode 2///
4726
+ ////////////
4727
+
4728
+ if (mode >= 2) {//Laguerre's method
4729
+ one_nth = 1.0 / (degree); ///
4730
+ n_1_nth = (degree - 1) * one_nth; ////
4731
+ two_n_div_n_1 = 2.0 / n_1_nth;
4732
+ c_one_nth = complex(one_nth, 0.0);
4733
+
4734
+ for (i = 1; i <= MAXIT; i++) {
4735
+ faq = 1.0;
4736
+
4737
+ //prepare stoping criterion
4738
+ ek = abs(poly[degree]);
4739
+ absroot = abs(*root);
4740
+ //calculate value of polynomial and its first two derivative
4741
+ p = poly[degree];
4742
+ dp = zero;
4743
+ d2p_half = zero;
4744
+ for (k = degree; k >= 1; k--) {//Horner Scheme, see for eg. Numerical Recipes Sec. 5.3 how to evaluate polynomials and derivatives
4745
+ d2p_half = dp + d2p_half * (*root);
4746
+ dp = p + dp * (*root);
4747
+ p = poly[k - 1] + p * (*root); // b_k
4748
+ //Adams, Duane A., 1967, "A stopping criterion for polynomial root finding",
4749
+ //Communications of the ACM, Volume 10 Issue 10, Oct. 1967, p. 655
4750
+ //ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/67/55/CS-TR-67-55.pdf
4751
+ //Eq 8.
4752
+ ek = absroot * ek + abs(p);
4753
+ }
4754
+ abs2p = real(conj(p) * p); // abs(p)
4755
+ iter = iter + 1;
4756
+ if (abs2p == 0) return;
4757
+
4758
+ stopping_crit2 = pow(FRAC_ERR * ek, 2);
4759
+ if (abs2p < stopping_crit2) {//(simplified a little Eq. 10 of Adams 1967)
4760
+ //do additional iteration if we are less than 10x from stopping criterion
4761
+ if (abs2p < 0.01*stopping_crit2) return; // ten times better than stopping criterion
4762
+ //return immediately, because we are at very good place
4763
+ else {
4764
+ good_to_go = true; //do one iteration more
4765
+ }
4766
+ }
4767
+ else {
4768
+ good_to_go = false; //reset if we are outside the zone of the root
4769
+ }
4770
+
4771
+ denom = zero;
4772
+ if (dp != zero) {
4773
+ fac_netwon = p / dp;
4774
+ fac_extra = d2p_half / dp;
4775
+ F_half = fac_netwon * fac_extra;
4776
+
4777
+ abs2_F_half = real(conj(F_half) * F_half);
4778
+ if (abs2_F_half <= 0.0625) {//F<0.50, F/2<0.25
4779
+ //go to SG method
4780
+ if (abs2_F_half <= 0.000625) {//F<0.05, F/2<0.02
4781
+ mode = 0; //go to Newton's
4782
+ }
4783
+ else {
4784
+ mode = 1; //go to SG
4785
+ }
4786
+ }
4787
+
4788
+ denom_sqrt = sqrt(c_one - two_n_div_n_1*F_half);
4789
+
4790
+ //NEXT LINE PROBABLY CAN BE COMMENTED OUT
4791
+ if (real(denom_sqrt) > 0.0) {
4792
+ //real part of a square root is positive for probably all compilers. You can \F9
4793
+ //test this on your compiler and if so, you can omit this check
4794
+ denom = c_one_nth + n_1_nth * denom_sqrt;
4795
+ }
4796
+ else {
4797
+ denom = c_one_nth - n_1_nth * denom_sqrt;
4798
+ }
4799
+ }
4800
+ if (denom == zero) {//test if demoninators are > 0.0 not to divide by zero
4801
+ dx = (abs(*root) + 1.0) + expcmplx(complex(0.0, FRAC_JUMPS[i% FRAC_JUMP_LEN] * 2 * M_PI)); //make some random jump
4802
+ }
4803
+ else {
4804
+ dx = fac_netwon / denom;
4805
+ }
4806
+ newroot = *root - dx;
4807
+ if (newroot == *root) return; // nothing changes -> return
4808
+ if (good_to_go) {//this was jump already after stopping criterion was met
4809
+ *root = newroot;
4810
+ return;
4811
+ }
4812
+ if (mode != 2) {
4813
+ *root = newroot;
4814
+ j = i + 1; //remember iteration index
4815
+ break; //go to Newton's or SG
4816
+ }
4817
+ if ((i% FRAC_JUMP_EVERY) == 0) {//decide whether to do a jump of modified length (to break cycles)
4818
+ faq = FRAC_JUMPS[((i / FRAC_JUMP_EVERY - 1) % FRAC_JUMP_LEN)];
4819
+ newroot = *root - faq * dx; // do jump of some semi-random length (0 < faq < 1)
4820
+ }
4821
+ *root = newroot;
4822
+ } //do mode 2
4823
+
4824
+ if (i >= MAXIT) {
4825
+ success = false;
4826
+ return;
4827
+ }
4828
+ }
4829
+
4830
+ ////////////
4831
+ ///mode 1///
4832
+ ////////////
4833
+
4834
+ if (mode == 1) {//SECOND-ORDER GENERAL METHOD (SG)
4835
+
4836
+ for (i = j; i <= MAXIT; i++) {
4837
+ faq = 1.0;
4838
+ //calculate value of polynomial and its first two derivatives
4839
+ p = poly[degree];
4840
+ dp = zero;
4841
+ d2p_half = zero;
4842
+ if ((i - j) % 10 == 0) {
4843
+ //prepare stopping criterion
4844
+ ek = abs(poly[degree]);
4845
+ absroot = abs(*root);
4846
+ for (k = degree; k >= 1; k--) {//Horner Scheme, see for eg. Numerical Recipes Sec. 5.3 how to evaluate polynomials and derivatives
4847
+ d2p_half = dp + d2p_half * (*root);
4848
+ dp = p + dp * (*root);
4849
+ p = poly[k - 1] + p * (*root); //b_k
4850
+ //Adams, Duane A., 1967, "A stopping criterion for polynomial root finding",
4851
+ //Communications of the ACM, Volume 10 Issue 10, Oct. 1967, p. 655
4852
+ //ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/67/55/CS-TR-67-55.pdf
4853
+ //Eq 8.
4854
+ ek = absroot * ek + abs(p);
4855
+ }
4856
+ stopping_crit2 = pow(FRAC_ERR*ek, 2);
4857
+ }
4858
+ else {
4859
+ for (k = degree; k >= 1; k--) {//Horner Scheme, see for eg. Numerical Recipes Sec. 5.3 how to evaluate polynomials and derivatives
4860
+ d2p_half = dp + d2p_half * (*root);
4861
+ dp = p + dp * (*root);
4862
+ p = poly[k - 1] + p * (*root); //b_k
4863
+ }
4864
+ }
4865
+ abs2p = real(conj(p) * p); //abs(p)**2
4866
+ iter = iter + 1;
4867
+ if (abs2p == 0.0) return;
4868
+
4869
+ if (abs2p < stopping_crit2) {//(simplified a little Eq. 10 of Adams 1967)
4870
+ if (dp == zero) return;
4871
+ //do additional iteration if we are less than 10x from stopping criterion
4872
+ if (abs2p < 0.01*stopping_crit2) return; //ten times better than stopping criterion
4873
+ //ten times better than stopping criterion
4874
+ else {
4875
+ good_to_go = true; //do one iteration more
4876
+ }
4877
+ }
4878
+ else {
4879
+ good_to_go = false; //reset if we are outside the zone of the root
4880
+ }
4881
+ if (dp == zero) {//test if denominators are > 0.0 not to divide by zero
4882
+ dx = (abs(*root) + 1.0) * expcmplx(complex(0.0, FRAC_JUMPS[i% FRAC_JUMP_LEN] * 2 * M_PI)); //make some random jump
4883
+ }
4884
+ else {
4885
+ fac_netwon = p / dp;
4886
+ fac_extra = d2p_half / dp;
4887
+ F_half = fac_netwon * fac_extra;
4888
+
4889
+ abs2_F_half = real(conj(F_half) * F_half);
4890
+ if (abs2_F_half <= 0.000625) {//F<0.05, F/2<0.025
4891
+ mode = 0; //set Newton's, go there after jump
4892
+ }
4893
+ dx = fac_netwon * (c_one + F_half); //SG
4894
+ }
4895
+ newroot = *root - dx;
4896
+ if (newroot == *root) return; //nothing changes -> return
4897
+ if (good_to_go) {
4898
+ *root = newroot; //this was jump already after stopping criterion was met
4899
+ return;
4900
+ }
4901
+ if (mode != 1) {
4902
+ *root = newroot;
4903
+ j = i + 1; //remember iteration number
4904
+ break; //go to Newton's
4905
+ }
4906
+ if ((i% FRAC_JUMP_EVERY) == 0) {// decide whether to do a jump of modified length (to break cycles)
4907
+ faq = FRAC_JUMPS[(i / FRAC_JUMP_EVERY - 1) % FRAC_JUMP_LEN];
4908
+ newroot = *root - faq * dx; //do jump of some semi random lenth (0 < faq < 1)
4909
+ }
4910
+ *root = newroot;
4911
+ }
4912
+ if (i >= MAXIT) {
4913
+ success = false;
4914
+ return;
4915
+ }
4916
+
4917
+ }
4918
+ //------------------------------------------------------------------------------- mode 0
4919
+ if (mode == 0) { // Newton's Method
4920
+
4921
+ for (i = j; i <= j + 10; i++) { // Do only 10 iterations the most then go back to Laguerre
4922
+ faq = 1.0;
4923
+
4924
+ //calc polynomial and first two derivatives
4925
+ p = poly[degree];
4926
+ dp = zero;
4927
+ if (i == j) { // Calculating stopping criterion only at the beginning
4928
+ ek = abs(poly[degree]);
4929
+ absroot = abs(*root);
4930
+ for (k = degree; k >= 1; k--) {
4931
+ dp = p + dp*(*root);
4932
+ p = poly[k - 1] + p*(*root);
4933
+ ek = absroot*ek + abs(p);
4934
+ }
4935
+ stopping_crit2 = pow(FRAC_ERR*ek, 2.0);
4936
+ }
4937
+ else {
4938
+ for (k = degree; k >= 1; k--) {
4939
+ dp = p + dp*(*root);
4940
+ p = poly[k - 1] + p*(*root);
4941
+ }
4942
+ }
4943
+ abs2p = real(conj(p)*p);
4944
+ iter = iter + 1;
4945
+ if (abs2p == 0.0) return;
4946
+
4947
+ if (abs2p < stopping_crit2) {
4948
+ if (dp == zero) return;
4949
+ // do additional iteration if we are less than 10x from stopping criterion
4950
+ if (abs2p < 0.01*stopping_crit2) {
4951
+ return; // return immediately since we are at a good place
4952
+ }
4953
+ else {
4954
+ good_to_go = true; // do one more iteration
4955
+ }
4956
+ }
4957
+ else {
4958
+ good_to_go = false;
4959
+ }
4960
+
4961
+ if (dp == zero) {
4962
+ dx = (abs(*root) + 1.0)*expcmplx(complex(0.0, 2 * M_PI*FRAC_JUMPS[i % FRAC_JUMP_LEN])); // make a random jump
4963
+ }
4964
+ else {
4965
+ dx = p / dp;
4966
+ }
4967
+
4968
+ newroot = *root - dx;
4969
+ if (newroot == *root) return;
4970
+ if (good_to_go) {
4971
+ *root = newroot;
4972
+ return;
4973
+ }
4974
+ *root = newroot;
4975
+ }
4976
+ if (iter >= MAXIT) {
4977
+ //too many iterations
4978
+ success = false;
4979
+ return;
4980
+ }
4981
+ mode = 2; //go back to Laguerre's. Happens when could not converge with 10 steps of Newton
4982
+ }
4983
+
4984
+ }/// end of infinite loop
4985
+ }
4986
+