00001 #include "astro.h"
00002 #include "jsoc_main.h"
00003 #include "list.h"
00004
00005 #define DEBUG 0
00006
00007
00008
00009
00010 #define kXGCI "GCIEC_X"
00011 #define kYGCI "GCIEC_Y"
00012 #define kZGCI "GCIEC_Z"
00013 #define kVXGCI "GCIEC_VX"
00014 #define kVYGCI "GCIEC_VY"
00015 #define kVZGCI "GCIEC_VZ"
00016 #define kXHCI "HCIEC_X"
00017 #define kYHCI "HCIEC_Y"
00018 #define kZHCI "HCIEC_Z"
00019 #define kVXHCI "HCIEC_VX"
00020 #define kVYHCI "HCIEC_VY"
00021 #define kVZHCI "HCIEC_VZ"
00022 #define kOBSDATE "OBS_DATE"
00023
00024
00025
00026 #define kRSUNOBS "RSUN_OBS"
00027 #define kOBSVR "OBS_VR"
00028 #define kDSUNOBS "DSUN_OBS"
00029
00030 #define kMaxRecIdSize 128
00031
00032 #define kCACHEKEYSIZE 64
00033 #define kCACHESIZE 128
00034
00035 #define kPI M_PI
00036 #define kDEG2RAD (kPI / 180)
00037
00038
00039 #define kALPHA (75.76 * kDEG2RAD)
00040 #define kDELTA (7.25 * kDEG2RAD)
00041
00042 #define kRSUNREF 696000000.00
00043
00044
00045 #define TWO_PI (2*kPI)
00046 #define C (299792.458) // c in km/s
00047 #define CARR_DEGDAY (14.1844000) // Adopted degrees per day, includes precession
00048 #define T2000 (725760032.0) // sscan_time("2000.01.01_00") J2000 base time
00049 #define TCARR (-3881476800.0) // sscan_time("1854.01.01_12:00_TAI") Carr ref epcoh est.
00050 #define CARR_ROT_SYNODIC (27.275311 * 86400.0) // estimate of synodic carrington rotation period
00051 #define DEGRAD (180.0/kPI)
00052
00053 enum IORBIT_Slotpos_enum
00054 {
00055 kMISSING = 0,
00056 kLT,
00057 kGT,
00058 kEQ,
00059 kLTE,
00060 kGTE
00061 };
00062
00063 typedef enum IORBIT_Slotpos_enum IORBIT_Slotpos_t;
00064
00065 struct IORBIT_Vector_struct
00066 {
00067 long long slot;
00068 double obstime;
00069 double gciX;
00070 double gciY;
00071 double gciZ;
00072 double gciVX;
00073 double gciVY;
00074 double gciVZ;
00075 double hciX;
00076 double hciY;
00077 double hciZ;
00078 double hciVX;
00079 double hciVY;
00080 double hciVZ;
00081 double rsunobs;
00082 double obsvr;
00083 double dsunobs;
00084 };
00085
00086 typedef struct IORBIT_Vector_struct IORBIT_Vector_t;
00087
00088
00089
00090
00091 static int gCacheChunking = 1;
00092 static IORBIT_Vector_t *gGridCache = NULL;
00093 static DRMS_RecordSet_t *gCacheRS = NULL;
00094 static int gGridNItems = 0;
00095 static int gGridCurrPos = -1;
00096 static HContainer_t *gKeyMap = NULL;
00097
00098
00099 const int gMinAbove = 16;
00100 const int gMinBelow = 16;
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 static void SDOCarringtonCoords(TIME t, double obsdist, double b, double hci_long, int *crot, double *L, double *B)
00112 {
00113 double solrots;
00114 double carr_rots;
00115 double l;
00116 double tlight;
00117 double clest;
00118 int rot;
00119
00120 tlight = obsdist/C;
00121 solrots = (CARR_DEGDAY * (t - tlight - TCARR)/86400 -0.125)/DEGRAD;
00122 l = hci_long - solrots;
00123 l = modf(l/TWO_PI, &carr_rots);
00124 if(l < 0) l += 1;
00125
00126
00127
00128 carr_rots = 3.0 + (t - tlight - TCARR)/CARR_ROT_SYNODIC;
00129 rot = (int)carr_rots;
00130 clest = (1 + rot - carr_rots);
00131 if ((l - clest) > 0.5)
00132 rot++;
00133 if ((clest - l) > 0.5)
00134 rot--;
00135
00136 *crot = rot;
00137 *L = 360*l;
00138 *B = b * DEGRAD;
00139 }
00140
00141
00142 static int CmpTimes(const void *a, const void *b)
00143 {
00144 double *aa = (double *)a;
00145 double *bb = (double *)b;
00146
00147 if (aa && bb)
00148 {
00149 if (drms_ismissing_time(*aa) && drms_ismissing_time(*bb))
00150 {
00151 return 0;
00152 }
00153 else if (drms_ismissing_time(*aa))
00154 {
00155 return -1;
00156 }
00157 else if (drms_ismissing_time(*bb))
00158 {
00159 return 1;
00160 }
00161 else
00162 {
00163 return (*aa < *bb ? -1 : (*aa == *bb ? 0 : 1));
00164 }
00165 }
00166 else if (aa)
00167 {
00168 return 1;
00169 }
00170 else if (bb)
00171 {
00172 return -1;
00173 }
00174 else
00175 {
00176 return 0;
00177 }
00178 }
00179
00180
00181
00182
00183 static int SortTimes(const double *unsorted, int nitems, double **sorted)
00184 {
00185 int nret = 0;
00186 double *sortedint = malloc(nitems * sizeof(double));
00187 int itime;
00188
00189 if (sortedint)
00190 {
00191 memcpy(sortedint, unsorted, nitems * sizeof(double));
00192 qsort(sortedint, nitems, sizeof(double), CmpTimes);
00193
00194 if (sorted)
00195 {
00196 itime = 0;
00197 while (drms_ismissing_time(sortedint[itime]) && itime < nitems)
00198 {
00199 itime++;
00200 }
00201
00202
00203 if (itime < nitems)
00204 {
00205
00206 nret = nitems - itime;
00207 *sorted = malloc(nret * sizeof(double));
00208 memcpy(*sorted, &(sortedint[itime]), nret * sizeof(double));
00209 }
00210 }
00211
00212 free(sortedint);
00213 sortedint = NULL;
00214 }
00215 else
00216 {
00217 fprintf(stderr, "SortTime() - out of memory.\n");
00218 }
00219
00220 return nret;
00221 }
00222
00223
00224 static int SortTimesB(const double *unsorted, int nitems, double **sorted)
00225 {
00226 int nret = 0;
00227 double *sortedint = malloc(nitems * sizeof(double));
00228
00229 if (sortedint)
00230 {
00231 memcpy(sortedint, unsorted, nitems * sizeof(double));
00232 qsort(sortedint, nitems, sizeof(double), CmpTimes);
00233
00234 if (sorted)
00235 {
00236 nret = nitems;
00237 *sorted = malloc(nret * sizeof(double));
00238 memcpy(*sorted, sortedint, nret * sizeof(double));
00239 }
00240
00241 free(sortedint);
00242 sortedint = NULL;
00243 }
00244 else
00245 {
00246 fprintf(stderr, "SortTime() - out of memory.\n");
00247 }
00248
00249 return nret;
00250 }
00251
00252
00253 static IORBIT_Slotpos_t GetSlotPos(double slottime, double tgttime)
00254 {
00255 IORBIT_Slotpos_t slotpos;
00256
00257 if (!drms_ismissing_time(slottime))
00258 {
00259 if (slottime < tgttime)
00260 {
00261 slotpos = kLT;
00262 }
00263 else if (slottime > tgttime)
00264 {
00265 slotpos = kGT;
00266 }
00267 else
00268 {
00269 slotpos = kEQ;
00270 }
00271 }
00272 else
00273 {
00274 slotpos = kMISSING;
00275 }
00276
00277 return slotpos;
00278 }
00279
00280
00281 static int IsPos(IORBIT_Slotpos_t posA, IORBIT_Slotpos_t posB)
00282 {
00283 return ((posA == kLT && (posB == kLTE || posB == kLT)) ||
00284 (posA == kGT && (posB == kGTE || posB == kGT)) ||
00285 (posA == kEQ && posB == kLTE) ||
00286 (posA == kEQ && posB == kGTE) ||
00287 (posA == posB));
00288 }
00289
00290
00291
00292
00293
00294
00295
00296 static inline int CreateLHashKey(char *hashkey, int size, long long slot)
00297 {
00298 return snprintf(hashkey, size, "%lld", slot);
00299 }
00300
00301 static inline int CreateDHashKey(char *hashkey, int size, double val)
00302 {
00303 return snprintf(hashkey, size, "%f", val);
00304 }
00305
00306 static IORBIT_Vector_t *CreateCache()
00307 {
00308 if (!gGridCache)
00309 {
00310 gGridCache = (IORBIT_Vector_t *)malloc(sizeof(IORBIT_Vector_t) * kCACHESIZE);
00311 }
00312
00313 return gGridCache;
00314 }
00315
00316 static void DestroyCache()
00317 {
00318 if (gCacheRS)
00319 {
00320 drms_close_records(gCacheRS, DRMS_FREE_RECORD);
00321 gCacheRS = NULL;
00322 }
00323
00324 if (gGridCache)
00325 {
00326 free(gGridCache);
00327 gGridCache = NULL;
00328 }
00329 }
00330
00331
00332 static IORBIT_Vector_t *LookupInCache(double tgttime, IORBIT_Slotpos_t pos)
00333 {
00334 IORBIT_Vector_t *val = NULL;
00335 IORBIT_Vector_t *vec = NULL;
00336 int icache;
00337 int top;
00338 int bottom;
00339 int direction;
00340 IORBIT_Slotpos_t slotpos;
00341
00342 if (gGridCache)
00343 {
00344 top = gGridNItems - 1;
00345 bottom = 0;
00346
00347 if (IsPos(pos, kLTE))
00348 {
00349 direction = -1;
00350 }
00351 else
00352 {
00353 direction = 1;
00354 }
00355
00356 if (direction == -1)
00357 {
00358 while (top != bottom)
00359 {
00360 icache = (int)ceil((double)(top + bottom) / 2);
00361 vec = &(gGridCache[icache]);
00362 slotpos = GetSlotPos(vec->obstime, tgttime);
00363 if (IsPos(slotpos, pos))
00364 {
00365
00366
00367
00368
00369 bottom = icache;
00370 }
00371 else
00372 {
00373
00374
00375
00376 top = icache - 1;
00377 }
00378 }
00379 }
00380 else
00381 {
00382 while (top != bottom)
00383 {
00384 icache = (int)floor((double)(top + bottom) / 2);
00385 vec = &(gGridCache[icache]);
00386 slotpos = GetSlotPos(vec->obstime, tgttime);
00387 if (IsPos(slotpos, pos))
00388 {
00389
00390
00391
00392
00393 top = icache;
00394 }
00395 else
00396 {
00397
00398
00399
00400 bottom = icache + 1;
00401 }
00402 }
00403 }
00404
00405
00406 vec = &(gGridCache[top]);
00407
00408
00409
00410 slotpos = GetSlotPos(vec->obstime, tgttime);
00411 if (IsPos(slotpos, pos))
00412 {
00413 val = vec;
00414 gGridCurrPos = top;
00415 }
00416 else
00417 {
00418 gGridCurrPos = -1;
00419 }
00420 }
00421
00422 return val;
00423 }
00424
00425 static double GetKey(DRMS_Record_t *rec, const char *keyID)
00426 {
00427 const char *keyname = NULL;
00428
00429 keyname = (const char *)hcon_lookup(gKeyMap, keyID);
00430 if (keyname)
00431 {
00432 return drms_getkey_double(rec, keyname, NULL);
00433 }
00434 else
00435 {
00436 return DRMS_MISSING_DOUBLE;
00437 }
00438 }
00439
00440 static void PopulateVector(DRMS_Record_t *rec, IORBIT_Vector_t *vec)
00441 {
00442 const char *keyname = NULL;
00443 char indxkey[DRMS_MAXKEYNAMELEN] = {0};
00444
00445 if (gKeyMap)
00446 {
00447
00448
00449
00450 vec->obstime = GetKey(rec, "kOBSDATE");
00451 vec->gciX = GetKey(rec, "kXGCI");
00452 vec->gciY = GetKey(rec, "kYGCI");
00453 vec->gciZ = GetKey(rec, "kZGCI");
00454 vec->gciVX = GetKey(rec, "kVXGCI");
00455 vec->gciVY = GetKey(rec, "kVYGCI");
00456 vec->gciVZ = GetKey(rec, "kVZGCI");
00457 vec->hciX = GetKey(rec, "kXHCI");
00458 vec->hciY = GetKey(rec, "kYHCI");
00459 vec->hciZ = GetKey(rec, "kZHCI");
00460 vec->hciVX = GetKey(rec, "kVXHCI");
00461 vec->hciVY = GetKey(rec, "kVYHCI");
00462 vec->hciVZ = GetKey(rec, "kVZHCI");
00463 vec->rsunobs = GetKey(rec, "kRSUNOBS");
00464 vec->obsvr = GetKey(rec, "kOBSVR");
00465 vec->dsunobs = GetKey(rec, "kDSUNOBS");
00466
00467 keyname = (const char *)hcon_lookup(gKeyMap, "kOBSDATE");
00468 if (keyname)
00469 {
00470 snprintf(indxkey, sizeof(indxkey), "%s_index", keyname);
00471 }
00472 }
00473 else
00474 {
00475
00476 vec->obstime = drms_getkey_double(rec, kOBSDATE, NULL);
00477 vec->gciX = drms_getkey_double(rec, kXGCI, NULL);
00478 vec->gciY = drms_getkey_double(rec, kYGCI, NULL);
00479 vec->gciZ = drms_getkey_double(rec, kZGCI, NULL);
00480 vec->gciVX = drms_getkey_double(rec, kVXGCI, NULL);
00481 vec->gciVY = drms_getkey_double(rec, kVYGCI, NULL);
00482 vec->gciVZ = drms_getkey_double(rec, kVZGCI, NULL);
00483 vec->hciX = drms_getkey_double(rec, kXHCI, NULL);
00484 vec->hciY = drms_getkey_double(rec, kYHCI, NULL);
00485 vec->hciZ = drms_getkey_double(rec, kZHCI, NULL);
00486 vec->hciVX = drms_getkey_double(rec, kVXHCI, NULL);
00487 vec->hciVY = drms_getkey_double(rec, kVYHCI, NULL);
00488 vec->hciVZ = drms_getkey_double(rec, kVZHCI, NULL);
00489
00490
00491 vec->rsunobs = DRMS_MISSING_DOUBLE;
00492 vec->obsvr = DRMS_MISSING_DOUBLE;
00493 vec->dsunobs = DRMS_MISSING_DOUBLE;
00494
00495 snprintf(indxkey, sizeof(indxkey), "%s_index", kOBSDATE);
00496 }
00497
00498 vec->slot = drms_getkey_longlong(rec, indxkey, NULL);
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 static int RehydrateCache(DRMS_Env_t *env,
00512 const char *srcseries,
00513 const char *optfilter,
00514 int nkeep)
00515 {
00516 int nitems = 0;
00517 int ret = 0;
00518
00519 IORBIT_Vector_t *vec;
00520 DRMS_Record_t *rec = NULL;
00521 int iitem = 0;
00522 char query[256];
00523 int drmsstatus;
00524 DRMS_RecChunking_t cstat = kRecChunking_None;
00525 int newchunk;
00526 int firstitem = 0;
00527 int lastitem = 0;
00528
00529 snprintf(query,
00530 sizeof(query),
00531 "%s%s",
00532 srcseries, optfilter ? optfilter : "");
00533
00534 if (!gCacheChunking)
00535 {
00536 if (gCacheRS)
00537 {
00538
00539 fprintf(stderr, "Cannot rehydrate cache if caching is turned off.\n");
00540 }
00541 else
00542 {
00543
00544 gCacheRS = drms_open_records(env, query, &drmsstatus);
00545
00546 if (gCacheRS && gCacheRS->n > 0)
00547 {
00548 gGridCache = (IORBIT_Vector_t *)malloc(sizeof(IORBIT_Vector_t) * gCacheRS->n);
00549 firstitem = 0;
00550 lastitem = gCacheRS->n;
00551
00552 for (iitem = firstitem; iitem < lastitem; iitem++)
00553 {
00554 rec = gCacheRS->records[iitem];
00555 vec = &(gGridCache[iitem]);
00556
00557
00558
00559
00560
00561 PopulateVector(rec, vec);
00562 }
00563 }
00564 }
00565
00566 nitems = lastitem - firstitem;
00567 gGridNItems = nitems;
00568 ret = nitems;
00569 }
00570 else
00571 {
00572
00573 int newcache = 0;
00574
00575 if (!gGridCache)
00576 {
00577 gGridCache = CreateCache();
00578 newcache = 1;
00579 }
00580
00581 if (!gCacheRS)
00582 {
00583
00584 drms_recordset_setchunksize(kCACHESIZE);
00585 gCacheRS = drms_open_recordset(env, query, &drmsstatus);
00586 }
00587
00588
00589 if (newcache)
00590 {
00591 nkeep = 0;
00592 }
00593
00594 lastitem = kCACHESIZE - 1;
00595 firstitem = nkeep;
00596
00597
00598
00599 for (iitem = 0; iitem < nkeep; iitem++)
00600 {
00601 gGridCache[iitem] = gGridCache[gGridNItems - nkeep + iitem];
00602 }
00603
00604
00605 memset(gGridCache + nkeep, 0, sizeof(IORBIT_Vector_t) * (kCACHESIZE - nkeep));
00606
00607 for (iitem = firstitem; iitem <= lastitem; iitem++)
00608 {
00609 rec = drms_recordset_fetchnext(env, gCacheRS, &drmsstatus, &cstat, &newchunk);
00610 if (!rec)
00611 {
00612
00613 break;
00614 }
00615
00616 vec = &(gGridCache[iitem]);
00617
00618
00619
00620
00621
00622 PopulateVector(rec, vec);
00623 }
00624
00625 nitems = iitem - firstitem + nkeep;
00626 gGridNItems = nitems;
00627 ret = nitems - nkeep;
00628 }
00629
00630 return ret;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652 static IORBIT_Vector_t *Fetch(DRMS_Env_t *env,
00653 const char *srcseries,
00654 const char *optfilter,
00655 double tgttime,
00656 int nkeep,
00657 IORBIT_Slotpos_t pos)
00658 {
00659 IORBIT_Vector_t *vec = NULL;
00660 int again;
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672 again = 1;
00673
00674 while (again)
00675 {
00676 vec = LookupInCache(tgttime, pos);
00677
00678 if (vec)
00679 {
00680 if (!(gGridCurrPos == gGridNItems - 1 && (pos == kLT || pos == kLTE)))
00681 {
00682
00683
00684
00685
00686
00687
00688
00689 again = 0;
00690 }
00691 else if (!gCacheChunking)
00692 {
00693
00694
00695
00696
00697 fprintf(stderr,
00698 "WARNING: There might be an insufficient number of records in '%s%s' to span the range needed for interpolation.\n",
00699 srcseries,
00700 optfilter);
00701 again = 0;
00702 }
00703 }
00704 else
00705 {
00706 again = 1;
00707 }
00708
00709 if (again)
00710 {
00711
00712
00713 TIMER_t *tmr = NULL;
00714
00715 if (env->verbose)
00716 {
00717
00718 tmr = CreateTimer();
00719 }
00720
00721 if (RehydrateCache(env, srcseries, optfilter, nkeep) == 0)
00722 {
00723
00724
00725
00726
00727
00728 again = 0;
00729 }
00730
00731 if (env->verbose)
00732 {
00733 fprintf(stdout, "RehydrateCache() seconds elapsed: %f\n", GetElapsedTime(tmr));
00734 DestroyTimer(&tmr);
00735 }
00736 }
00737 }
00738
00739 return vec;
00740 }
00741
00742 static IORBIT_Vector_t *FetchPrevious()
00743 {
00744 IORBIT_Vector_t *vec = NULL;
00745
00746
00747 if (gGridCurrPos > 0)
00748 {
00749 vec = &(gGridCache[--gGridCurrPos]);
00750 }
00751
00752 return vec;
00753 }
00754
00755 static IORBIT_Vector_t *FetchNext(DRMS_Env_t *env,
00756 const char *srcseries,
00757 const char *optfilter,
00758 int nkeep)
00759 {
00760 IORBIT_Vector_t *vec = NULL;
00761
00762 if (gGridCurrPos < gGridNItems - 1)
00763 {
00764 vec = &(gGridCache[++gGridCurrPos]);
00765 }
00766 else
00767 {
00768
00769 vec = Fetch(env, srcseries, optfilter, gGridCache[gGridNItems - 1].obstime, nkeep, kGT);
00770 }
00771
00772 return vec;
00773 }
00774
00775
00776
00777
00778
00779
00780 static int CheckCache(double mintgt, double maxtgt)
00781 {
00782 int ok = 1;
00783
00784 if (!gCacheChunking)
00785 {
00786
00787
00788 int itime;
00789 itime = gGridNItems - 1;
00790
00791 while (gGridNItems - 1 - itime < gMinAbove)
00792 {
00793 if (gGridCache[itime].obstime <= maxtgt)
00794 {
00795 ok = 0;
00796 break;
00797 }
00798
00799 itime--;
00800 }
00801
00802 itime = 0;
00803 while (itime < gMinBelow)
00804 {
00805 if (gGridCache[itime].obstime >= mintgt)
00806 {
00807 ok = 0;
00808 break;
00809 }
00810
00811 itime++;
00812 }
00813 }
00814
00815 return ok;
00816 }
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 static int GetGridVectors(DRMS_Env_t *env,
00828 const char *srcseries,
00829 double *tgttimes,
00830 int ntgts,
00831 int nbelow,
00832 IORBIT_Slotpos_t posbelow,
00833 int nabove,
00834 IORBIT_Slotpos_t posabove,
00835 LinkedList_t **gvectors,
00836 int *ngvecs,
00837 HContainer_t **indices,
00838 const char *optfilter)
00839 {
00840 int err = 0;
00841 int actpoints;
00842 int totpoints = 0;
00843 IORBIT_Vector_t *vec = NULL;
00844 IORBIT_Slotpos_t slotpos;
00845
00846
00847
00848
00849 IORBIT_Vector_t *vecsbelow = NULL;
00850 IORBIT_Vector_t *vecsabove = NULL;
00851 int itgt;
00852 int ibelow;
00853 int iabove;
00854 char lhashkey[128];
00855 char dhashkey[128];
00856
00857
00858
00859 HContainer_t *slottovecindex = NULL;
00860
00861 if (gvectors)
00862 {
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876 *gvectors = list_llcreate(sizeof(IORBIT_Vector_t), NULL);
00877 vecsbelow = (IORBIT_Vector_t *)malloc(sizeof(IORBIT_Vector_t) * nbelow);
00878 vecsabove = (IORBIT_Vector_t *)malloc(sizeof(IORBIT_Vector_t) * nabove);
00879 slottovecindex = hcon_create(sizeof(int), 128, NULL, NULL, NULL, NULL, 0);
00880
00881 if (indices)
00882 {
00883 *indices = hcon_create(sizeof(int), 128, NULL, NULL, NULL, NULL, 0);
00884 }
00885
00886 for (itgt = 0; itgt < ntgts; itgt++)
00887 {
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 vec = Fetch(env, srcseries, optfilter, tgttimes[itgt], nbelow + 4, posbelow);
00898
00899 if (!vec)
00900 {
00901 fprintf(stderr,
00902 "There is no grid vector smaller than %f in '%s'.\n",
00903 tgttimes[itgt],
00904 srcseries);
00905 err = 1;
00906 break;
00907 }
00908
00909 if (itgt == 0 && !gCacheChunking)
00910 {
00911 if (!CheckCache(tgttimes[0], tgttimes[ntgts - 1]))
00912 {
00913 fprintf(stderr, "Not enough data records in '%s%s' to perform interpolation.\n", srcseries, optfilter);
00914 err = 1;
00915 break;
00916 }
00917 }
00918
00919
00920 actpoints = 0;
00921 while (1)
00922 {
00923
00924
00925
00926 slotpos = GetSlotPos(vec->obstime, tgttimes[itgt]);
00927
00928 if (IsPos(slotpos, posbelow))
00929 {
00930 vecsbelow[nbelow - actpoints - 1] = *vec;
00931 actpoints++;
00932 }
00933
00934 if (actpoints == nbelow)
00935 {
00936 break;
00937 }
00938
00939
00940 vec = FetchPrevious();
00941 if (!vec)
00942 {
00943 fprintf(stderr,
00944 "Series '%s' missing a grid vector smaller than %f.\n",
00945 srcseries,
00946 tgttimes[itgt]);
00947
00948 err = 1;
00949 break;
00950 }
00951 }
00952
00953 if (err)
00954 {
00955 break;
00956 }
00957
00958
00959
00960
00961
00962
00963
00964
00965 for (ibelow = 0; ibelow < nbelow; ibelow++)
00966 {
00967 CreateLHashKey(lhashkey, sizeof(lhashkey), vecsbelow[ibelow].slot);
00968
00969 if (hcon_lookup(slottovecindex, lhashkey))
00970 {
00971 continue;
00972 }
00973
00974 list_llinserttail(*gvectors, &(vecsbelow[ibelow]));
00975 hcon_insert(slottovecindex, lhashkey, &totpoints);
00976 totpoints++;
00977 }
00978
00979
00980
00981
00982
00983
00984 if (indices)
00985 {
00986 CreateLHashKey(lhashkey, sizeof(lhashkey), vecsbelow[nbelow - 1].slot);
00987 int *pvindex = (int *)hcon_lookup(slottovecindex, lhashkey);
00988 CreateDHashKey(dhashkey, sizeof(dhashkey), tgttimes[itgt]);
00989
00990 if (pvindex)
00991 {
00992 hcon_insert(*indices, dhashkey, pvindex);
00993
00994 }
00995 }
00996
00997
00998 actpoints = 0;
00999
01000
01001
01002 vec = Fetch(env, srcseries, optfilter, tgttimes[itgt], nbelow + 4, posabove);
01003
01004 if (!vec)
01005 {
01006 fprintf(stderr,
01007 "There is no grid vector greater than %f in '%s'.\n",
01008 tgttimes[itgt],
01009 srcseries);
01010 err = 1;
01011 break;
01012 }
01013
01014 while (1)
01015 {
01016
01017 slotpos = GetSlotPos(vec->obstime, tgttimes[itgt]);
01018
01019 if (IsPos(slotpos, posabove))
01020 {
01021 vecsabove[actpoints] = *vec;
01022 actpoints++;
01023 }
01024
01025 if (actpoints == nabove)
01026 {
01027 break;
01028 }
01029
01030
01031
01032 vec = FetchNext(env, srcseries, optfilter, nbelow + 4);
01033 if (!vec)
01034 {
01035 fprintf(stderr,
01036 "Series '%s' missing a grid vector smaller than %f.\n",
01037 srcseries,
01038 tgttimes[itgt]);
01039 err = 1;
01040 break;
01041 }
01042 }
01043
01044 if (err)
01045 {
01046 break;
01047 }
01048
01049
01050 for (iabove = 0; iabove < nabove; iabove++)
01051 {
01052 CreateLHashKey(lhashkey, sizeof(lhashkey), vecsabove[iabove].slot);
01053
01054 if (hcon_lookup(slottovecindex, lhashkey))
01055 {
01056 continue;
01057 }
01058
01059 list_llinserttail(*gvectors, &(vecsabove[iabove]));
01060 hcon_insert(slottovecindex, lhashkey, &totpoints);
01061 totpoints++;
01062 }
01063 }
01064
01065 if (vecsbelow)
01066 {
01067 free(vecsbelow);
01068 }
01069
01070 if (vecsabove)
01071 {
01072 free(vecsabove);
01073 }
01074
01075 if (slottovecindex)
01076 {
01077 hcon_destroy(&slottovecindex);
01078 }
01079 }
01080
01081 if (ngvecs)
01082 {
01083 *ngvecs = totpoints;
01084 }
01085
01086 return err;
01087 }
01088
01089
01090 static int iorbit_interpolate(IORBIT_Alg_t alg,
01091 IORBIT_Vector_t *gridVecs,
01092 const double *tgttimes,
01093 HContainer_t *indexmap,
01094 int ntgtpts,
01095 IORBIT_Vector_t **interp)
01096 {
01097 int err = 0;
01098 int ipt;
01099 int vindex = 0;
01100 char dhashkey[128];
01101
01102 if (interp)
01103 {
01104 *interp = (IORBIT_Vector_t *)malloc(sizeof(IORBIT_Vector_t) * ntgtpts);
01105
01106 switch (alg)
01107 {
01108 case IORBIT_Alg_Linear:
01109 {
01110 fprintf(stderr, "Unsupported interpolation algorithm '%d'.\n", (int)alg);
01111 }
01112 break;
01113 case IORBIT_Alg_Quadratic:
01114 {
01115 double ptlow;
01116 double ptmid;
01117 double pthii;
01118 IORBIT_Vector_t *veclow = NULL;
01119 IORBIT_Vector_t *vecmid = NULL;
01120 IORBIT_Vector_t *vechii = NULL;
01121 double factorlow;
01122 double factormid;
01123 double factorhii;
01124
01125 for (ipt = 0; ipt < ntgtpts; ipt++)
01126 {
01127 if (drms_ismissing_time(tgttimes[ipt]))
01128 {
01129
01130 ((*interp)[ipt]).obstime = DRMS_MISSING_TIME;
01131 continue;
01132 }
01133
01134 CreateDHashKey(dhashkey, sizeof(dhashkey), tgttimes[ipt]);
01135 vindex = *((int *)hcon_lookup(indexmap, dhashkey));
01136
01137 ptlow = gridVecs[vindex - 1].obstime;
01138 ptmid = gridVecs[vindex].obstime;
01139 pthii = gridVecs[vindex + 1].obstime;
01140 veclow = &(gridVecs[vindex - 1]);
01141 vecmid = &(gridVecs[vindex]);
01142 vechii = &(gridVecs[vindex + 1]);
01143 factorlow = (tgttimes[ipt] - ptmid) * (tgttimes[ipt] - pthii) /
01144 ((ptlow - ptmid) * (ptlow - pthii));
01145 factormid = (tgttimes[ipt] - ptlow) * (tgttimes[ipt] - pthii) /
01146 ((ptmid - ptlow) * (ptmid - pthii));
01147 factorhii = (tgttimes[ipt] - ptlow) * (tgttimes[ipt] - ptmid) /
01148 ((pthii - ptlow) * (pthii - ptmid));
01149
01150 ((*interp)[ipt]).obstime = tgttimes[ipt];
01151 ((*interp)[ipt]).slot = DRMS_MISSING_LONGLONG;
01152
01153
01154 ((*interp)[ipt]).gciX =
01155 veclow->gciX * factorlow + vecmid->gciX * factormid + vechii->gciX * factorhii;
01156 ((*interp)[ipt]).gciY =
01157 veclow->gciY * factorlow + vecmid->gciY * factormid + vechii->gciY * factorhii;
01158 ((*interp)[ipt]).gciZ =
01159 veclow->gciZ * factorlow + vecmid->gciZ * factormid + vechii->gciZ * factorhii;
01160
01161
01162 if (!drms_ismissing_double(veclow->gciVX) && !drms_ismissing_double(vecmid->gciVX) && !drms_ismissing_double(vechii->gciVX))
01163 {
01164 ((*interp)[ipt]).gciVX =
01165 veclow->gciVX * factorlow + vecmid->gciVX * factormid + vechii->gciVX * factorhii;
01166 }
01167 else
01168 {
01169 ((*interp)[ipt]).gciVX = DRMS_MISSING_DOUBLE;
01170 }
01171
01172
01173 if (!drms_ismissing_double(veclow->gciVY) && !drms_ismissing_double(vecmid->gciVY) && !drms_ismissing_double(vechii->gciVY))
01174 {
01175 ((*interp)[ipt]).gciVY =
01176 veclow->gciVY * factorlow + vecmid->gciVY * factormid + vechii->gciVY * factorhii;
01177 }
01178 else
01179 {
01180 ((*interp)[ipt]).gciVY = DRMS_MISSING_DOUBLE;
01181 }
01182
01183
01184 if (!drms_ismissing_double(veclow->gciVZ) && !drms_ismissing_double(vecmid->gciVZ) && !drms_ismissing_double(vechii->gciVZ))
01185 {
01186 ((*interp)[ipt]).gciVZ =
01187 veclow->gciVZ * factorlow + vecmid->gciVZ * factormid + vechii->gciVZ * factorhii;
01188 }
01189 else
01190 {
01191 ((*interp)[ipt]).gciVZ = DRMS_MISSING_DOUBLE;
01192 }
01193
01194
01195 ((*interp)[ipt]).hciX =
01196 veclow->hciX * factorlow + vecmid->hciX * factormid + vechii->hciX * factorhii;
01197 ((*interp)[ipt]).hciY =
01198 veclow->hciY * factorlow + vecmid->hciY * factormid + vechii->hciY * factorhii;
01199 ((*interp)[ipt]).hciZ =
01200 veclow->hciZ * factorlow + vecmid->hciZ * factormid + vechii->hciZ * factorhii;
01201
01202
01203 if (!drms_ismissing_double(veclow->hciVX) && !drms_ismissing_double(vecmid->hciVX) && !drms_ismissing_double(vechii->hciVX))
01204 {
01205 ((*interp)[ipt]).hciVX =
01206 veclow->hciVX * factorlow + vecmid->hciVX * factormid + vechii->hciVX * factorhii;
01207 }
01208 else
01209 {
01210 ((*interp)[ipt]).hciVX = DRMS_MISSING_DOUBLE;
01211 }
01212
01213
01214 if (!drms_ismissing_double(veclow->hciVY) && !drms_ismissing_double(vecmid->hciVY) && !drms_ismissing_double(vechii->hciVY))
01215 {
01216 ((*interp)[ipt]).hciVY =
01217 veclow->hciVY * factorlow + vecmid->hciVY * factormid + vechii->hciVY * factorhii;
01218 }
01219 else
01220 {
01221 ((*interp)[ipt]).hciVY = DRMS_MISSING_DOUBLE;
01222 }
01223
01224
01225 if (!drms_ismissing_double(veclow->hciVZ) && !drms_ismissing_double(vecmid->hciVZ) && !drms_ismissing_double(vechii->hciVZ))
01226 {
01227 ((*interp)[ipt]).hciVZ =
01228 veclow->hciVZ * factorlow + vecmid->hciVZ * factormid + vechii->hciVZ * factorhii;
01229 }
01230 else
01231 {
01232 ((*interp)[ipt]).hciVZ = DRMS_MISSING_DOUBLE;
01233 }
01234
01235
01236 if (!drms_ismissing_double(veclow->rsunobs) && !drms_ismissing_double(vecmid->rsunobs) && !drms_ismissing_double(vechii->rsunobs))
01237 {
01238 ((*interp)[ipt]).rsunobs =
01239 veclow->rsunobs * factorlow + vecmid->rsunobs * factormid + vechii->rsunobs * factorhii;
01240 }
01241 else
01242 {
01243 ((*interp)[ipt]).rsunobs = DRMS_MISSING_DOUBLE;
01244 }
01245
01246
01247 if (!drms_ismissing_double(veclow->obsvr) && !drms_ismissing_double(vecmid->obsvr) && !drms_ismissing_double(vechii->obsvr))
01248 {
01249 ((*interp)[ipt]).obsvr =
01250 veclow->obsvr * factorlow + vecmid->obsvr * factormid + vechii->obsvr * factorhii;
01251 }
01252 else
01253 {
01254 ((*interp)[ipt]).obsvr = DRMS_MISSING_DOUBLE;
01255 }
01256
01257
01258 if (!drms_ismissing_double(veclow->dsunobs) && !drms_ismissing_double(vecmid->dsunobs) && !drms_ismissing_double(vechii->dsunobs))
01259 {
01260 ((*interp)[ipt]).dsunobs =
01261 veclow->dsunobs * factorlow + vecmid->dsunobs * factormid + vechii->dsunobs * factorhii;
01262 }
01263 else
01264 {
01265 ((*interp)[ipt]).dsunobs = DRMS_MISSING_DOUBLE;
01266 }
01267 }
01268 }
01269 break;
01270 default:
01271 err = 1;
01272 fprintf(stderr, "Unsupported interpolation algorithm '%d'.\n", (int)alg);
01273 }
01274 }
01275 else
01276 {
01277 err = 1;
01278 }
01279
01280 return err;
01281 }
01282
01283
01284
01285 static int CalcSolarVelocities(IORBIT_Vector_t *vec,
01286 int nvecs,
01287 double **hr,
01288 double **hvr,
01289 double **hvw,
01290 double **hvn,
01291 double **hb,
01292 double **hl)
01293 {
01294 int err = 0;
01295
01296 double shvx;
01297 double shvy;
01298 double shvz;
01299
01300 const double txx = cos(kALPHA);
01301 const double txy = sin(kALPHA);
01302 const double txz = 0.0;
01303 const double tyx = -sin(kALPHA) * cos(kDELTA);
01304 const double tyy = cos(kALPHA) * cos(kDELTA);
01305 const double tyz = sin(kDELTA);
01306 const double tzx = sin(kALPHA) * sin(kDELTA);
01307 const double tzy = -cos(kALPHA) * sin(kDELTA);
01308 const double tzz = cos(kDELTA);
01309
01310 *hr = (double *)malloc(sizeof(double) * nvecs);
01311
01312 if (hvr)
01313 {
01314 *hvr = (double *)malloc(sizeof(double) * nvecs);
01315 }
01316
01317 if (hvw)
01318 {
01319 *hvw = (double *)malloc(sizeof(double) * nvecs);
01320 }
01321
01322 if (hvn)
01323 {
01324 *hvn = (double *)malloc(sizeof(double) * nvecs);
01325 }
01326
01327 *hb = (double *)malloc(sizeof(double) * nvecs);
01328 *hl = (double *)malloc(sizeof(double) * nvecs);
01329
01330 IORBIT_Vector_t *cvec = NULL;
01331 int ivec;
01332 for (ivec = 0; ivec < nvecs; ivec++)
01333 {
01334 cvec = &(vec[ivec]);
01335
01336
01337 (*hr)[ivec] = sqrt(cvec->hciX * cvec->hciX +
01338 cvec->hciY * cvec->hciY +
01339 cvec->hciZ * cvec->hciZ);
01340
01341
01342
01343 (*hb)[ivec] = asin((tzx * cvec->hciX + tzy * cvec->hciY + tzz * cvec->hciZ) / (*hr)[ivec]);
01344 (*hl)[ivec] = atan2((tyx * cvec->hciX + tyy * cvec->hciY + tyz * cvec->hciZ),
01345 (txx * cvec->hciX + txy * cvec->hciY + txz * cvec->hciZ));
01346
01347
01348 shvx = txx * cvec->hciVX + txy * cvec->hciVY + txz * cvec->hciVZ;
01349 shvy = tyx * cvec->hciVX + tyy * cvec->hciVY + tyz * cvec->hciVZ;
01350 shvz = tzx * cvec->hciVX + tzy * cvec->hciVY + tzz * cvec->hciVZ;
01351
01352 if (hvr)
01353 {
01354 (*hvr)[ivec] = cos((*hb)[ivec]) * (cos((*hl)[ivec]) * shvx + sin((*hl)[ivec]) * shvy) + sin((*hb)[ivec]) * shvz;
01355 }
01356
01357 if (hvw)
01358 {
01359 (*hvw)[ivec] = -sin((*hl)[ivec]) * shvx + cos((*hl)[ivec]) * shvy;
01360 }
01361
01362 if (hvn)
01363 {
01364 (*hvn)[ivec] = -sin((*hb)[ivec]) * (cos((*hl)[ivec]) * shvx + sin((*hl)[ivec]) * shvy) + cos((*hb)[ivec]) * shvz;
01365 }
01366 }
01367
01368 return err;
01369 }
01370
01371 void iorbit_carrcoords(TIME t, double obsdist, double b, double hci_long, int *crot, double *L, double *B)
01372 {
01373 SDOCarringtonCoords(t, obsdist, b, hci_long, crot, L, B);
01374 }
01375
01376 static int SetUpKeymap(DRMS_Env_t *env, const char *series, HContainer_t *keymap)
01377 {
01378 int err = 0;
01379 const char *keyid = NULL;
01380 const char *keyname = NULL;
01381 HIterator_t *hit = NULL;
01382 int dstat = DRMS_SUCCESS;
01383 DRMS_Record_t *template = NULL;
01384
01385 if (keymap)
01386 {
01387
01388
01389 hit = hiter_create(keymap);
01390
01391 if (hit)
01392 {
01393 template = drms_template_record(env, series, &dstat);
01394
01395 if (template && dstat == DRMS_SUCCESS)
01396 {
01397 while ((keyname = hiter_extgetnext(hit, &keyid)) != NULL)
01398 {
01399 if (strcasecmp(keyid, "kXGCI") != 0 &&
01400 strcasecmp(keyid, "kYGCI") != 0 &&
01401 strcasecmp(keyid, "kZGCI") != 0 &&
01402 strcasecmp(keyid, "kVXGCI") != 0 &&
01403 strcasecmp(keyid, "kVYGCI") != 0 &&
01404 strcasecmp(keyid, "kVZGCI") != 0 &&
01405 strcasecmp(keyid, "kXHCI") != 0 &&
01406 strcasecmp(keyid, "kYHCI") != 0 &&
01407 strcasecmp(keyid, "kZHCI") != 0 &&
01408 strcasecmp(keyid, "kVXHCI") != 0 &&
01409 strcasecmp(keyid, "kVYHCI") != 0 &&
01410 strcasecmp(keyid, "kVZHCI") != 0 &&
01411 strcasecmp(keyid, "kOBSDATE") != 0 &&
01412 strcasecmp(keyid, "kRSUNOBS") != 0 &&
01413 strcasecmp(keyid, "kOBSVR") != 0 &&
01414 strcasecmp(keyid, "kDSUNOBS") != 0)
01415 {
01416 fprintf(stderr, "Invalid key ID %s.\n", keyid);
01417 err = 1;
01418 break;
01419 }
01420
01421 if (!drms_keyword_lookup(template, keyname, 1))
01422 {
01423 fprintf(stderr, "Invalid keyword name %s.\n", keyname);
01424 err = 1;
01425 break;
01426 }
01427
01428 if (!gKeyMap)
01429 {
01430 gKeyMap = hcon_create(DRMS_MAXKEYNAMELEN, DRMS_MAXKEYNAMELEN, NULL, NULL, NULL, NULL, 0);
01431 }
01432
01433 if (!gKeyMap)
01434 {
01435 fprintf(stderr, "Out of memory.\n");
01436 err = 1;
01437 }
01438 else
01439 {
01440 hcon_insert(gKeyMap, keyid, keyname);
01441 }
01442 }
01443
01444 if (err)
01445 {
01446 hcon_destroy(&gKeyMap);
01447 gKeyMap = NULL;
01448 }
01449 }
01450 else
01451 {
01452 fprintf(stderr, "Unable to get template record for series %s.\n", series);
01453 err = 1;
01454 }
01455
01456 hiter_destroy(&hit);
01457 }
01458 else
01459 {
01460 fprintf(stderr, "Out of memory.\n");
01461 err = 1;
01462 }
01463 }
01464
01465 return err;
01466 }
01467
01468 LIBASTRO_Error_t iorbit_getinfo_internal(DRMS_Env_t *env,
01469 const char *srcseries,
01470 const char *optfilter,
01471 IORBIT_Alg_t alg,
01472 const double *tgttimes,
01473 int nitems,
01474 IORBIT_CacheAction_t ctype,
01475 IORBIT_Info_t **info,
01476 int calcSolarV)
01477 {
01478 LIBASTRO_Error_t err = kLIBASTRO_Success;
01479 int ntimes = 0;
01480 double *tgtsorted = NULL;
01481 IORBIT_Info_t *retvec = NULL;
01482
01483 if (info && nitems > 0)
01484 {
01485 *info = calloc(nitems, sizeof(IORBIT_Info_t));
01486
01487
01488 ntimes = SortTimes(tgttimes, nitems, &tgtsorted);
01489 }
01490 else
01491 {
01492 err = kLIBASTRO_InvalidArgs;
01493 }
01494
01495 if (err == kLIBASTRO_Success && ntimes <= 0)
01496 {
01497
01498 int ivec;
01499
01500 for (ivec = 0; ivec < nitems; ivec++)
01501 {
01502 retvec = &((*info)[ivec]);
01503
01504
01505 retvec->obstime = DRMS_MISSING_TIME;
01506 retvec->hciX = DRMS_MISSING_DOUBLE;
01507 retvec->hciY = DRMS_MISSING_DOUBLE;
01508 retvec->hciZ = DRMS_MISSING_DOUBLE;
01509 retvec->hciVX = DRMS_MISSING_DOUBLE;
01510 retvec->hciVY = DRMS_MISSING_DOUBLE;
01511 retvec->hciVZ = DRMS_MISSING_DOUBLE;
01512 retvec->gciX = DRMS_MISSING_DOUBLE;
01513 retvec->gciY = DRMS_MISSING_DOUBLE;
01514 retvec->gciZ = DRMS_MISSING_DOUBLE;
01515 retvec->gciVX = DRMS_MISSING_DOUBLE;
01516 retvec->gciVY = DRMS_MISSING_DOUBLE;
01517 retvec->gciVZ = DRMS_MISSING_DOUBLE;
01518 retvec->dsun_obs = DRMS_MISSING_DOUBLE;
01519 retvec->rsun_obs = DRMS_MISSING_DOUBLE;
01520 retvec->obs_vr = DRMS_MISSING_DOUBLE;
01521 retvec->obs_vw = DRMS_MISSING_DOUBLE;
01522 retvec->obs_vn = DRMS_MISSING_DOUBLE;
01523 retvec->crln_obs = DRMS_MISSING_DOUBLE;
01524 retvec->crlt_obs = DRMS_MISSING_DOUBLE;
01525 retvec->car_rot = DRMS_MISSING_INT;
01526 snprintf(retvec->orb_rec, sizeof(retvec->orb_rec), "%s", DRMS_MISSING_STRING);
01527 }
01528 }
01529 else if (err == kLIBASTRO_Success)
01530 {
01531 LinkedList_t *listvecs = NULL;
01532 HContainer_t *indexmap = NULL;
01533 IORBIT_Vector_t *vecs = NULL;
01534 IORBIT_Vector_t *interp = NULL;
01535
01536 double *dsun_obs = NULL;
01537 double *hvr = NULL;
01538 double *hvw = NULL;
01539 double *hvn = NULL;
01540
01541 int nbelow = 0;
01542 int nabove = 0;
01543 char filter[DRMS_MAXQUERYLEN];
01544
01545 TIMER_t *tmr = NULL;
01546
01547 gCacheChunking = 1;
01548
01549 if (ctype == kIORBIT_CacheAction_Flush)
01550 {
01551 DestroyCache();
01552 }
01553 else if (ctype == kIORBIT_CacheAction_DontCache)
01554 {
01555 gCacheChunking = 0;
01556 DestroyCache();
01557
01558
01559
01560 if (optfilter != NULL)
01561 {
01562 fprintf(stderr, "WARNING: record-query filter '%s' is not applicable when caching is turned off and will not be used.\n", optfilter);
01563 }
01564 else
01565 {
01566
01567
01568 double min = tgtsorted[0];
01569 double max = tgtsorted[ntimes - 1];
01570 char mintime[128];
01571 char maxtime[128];
01572 sprint_time(mintime, min - 3600, "UTC", 0);
01573 sprint_time(maxtime, max + 3600, "UTC", 0);
01574
01575 snprintf(filter, sizeof(filter), "[%s-%s]", mintime, maxtime);
01576 optfilter = filter;
01577 }
01578 }
01579
01580 switch (alg)
01581 {
01582 case IORBIT_Alg_Linear:
01583 {
01584 fprintf(stderr, "Unsupported interpolation algorithm '%d'.\n", (int)alg);
01585 }
01586 break;
01587 case IORBIT_Alg_Quadratic:
01588 {
01589 nbelow = 2;
01590 nabove = 1;
01591 }
01592 break;
01593 default:
01594 fprintf(stderr, "Unsupported interpolation algorithm '%d'.\n", (int)alg);
01595 }
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617 if (env->verbose)
01618 {
01619
01620 tmr = CreateTimer();
01621 }
01622
01623 if (GetGridVectors(env,
01624 srcseries,
01625 tgtsorted,
01626 ntimes,
01627 nbelow,
01628 kLTE,
01629 nabove,
01630 kGT,
01631 &listvecs,
01632 NULL,
01633 &indexmap,
01634
01635
01636
01637 optfilter))
01638 {
01639 err = kLIBASTRO_InsufficientData;
01640 }
01641
01642
01643 free(tgtsorted);
01644
01645 if (env->verbose)
01646 {
01647 fprintf(stdout, "GetGridVectors() seconds elapsed: %f\n", GetElapsedTime(tmr));
01648 DestroyTimer(&tmr);
01649 }
01650
01651 if (!err && listvecs && indexmap)
01652 {
01653 int ivec;
01654 ListNode_t *ln = NULL;
01655
01656
01657 vecs = malloc(sizeof(IORBIT_Vector_t) * listvecs->nitems);
01658 list_llreset(listvecs);
01659 ivec = 0;
01660
01661 while ((ln = list_llnext(listvecs)) != NULL)
01662 {
01663 vecs[ivec++] = *((IORBIT_Vector_t *)(ln->data));
01664 }
01665
01666 if (env->verbose)
01667 {
01668
01669 tmr = CreateTimer();
01670 }
01671
01672
01673 if (!iorbit_interpolate(alg,
01674 vecs,
01675 tgttimes,
01676 indexmap,
01677 nitems,
01678 &interp))
01679 {
01680 double *hb = NULL;
01681 double *hl = NULL;
01682 int crot;
01683 double l0;
01684 double b0;
01685 char dhashkey[128];
01686 int *pvindex = NULL;
01687 int vindex;
01688 char tbuf[48];
01689
01690 if (env->verbose)
01691 {
01692 fprintf(stdout, "iorbit_interpolate() seconds elapsed: %f\n", GetElapsedTime(tmr));
01693 DestroyTimer(&tmr);
01694
01695
01696 tmr = CreateTimer();
01697 }
01698
01699 if (calcSolarV)
01700 {
01701 if (!CalcSolarVelocities(interp, nitems, &dsun_obs, &hvr, &hvw, &hvn, &hb, &hl))
01702 {
01703 if (env->verbose)
01704 {
01705 fprintf(stdout, "CalcSolarVelocities() seconds elapsed: %f\n", GetElapsedTime(tmr));
01706 DestroyTimer(&tmr);
01707 }
01708
01709
01710 for (ivec = 0; ivec < nitems; ivec++)
01711 {
01712 retvec = &((*info)[ivec]);
01713
01714
01715 SDOCarringtonCoords(interp[ivec].obstime, dsun_obs[ivec], hb[ivec], hl[ivec], &crot, &l0, &b0);
01716
01717 if (!drms_ismissing_time(interp[ivec].obstime))
01718 {
01719 retvec->obstime = interp[ivec].obstime;
01720
01721
01722 retvec->hciX = interp[ivec].hciX * 1000;
01723 retvec->hciY = interp[ivec].hciY * 1000;
01724 retvec->hciZ = interp[ivec].hciZ * 1000;
01725 retvec->hciVX = interp[ivec].hciVX * 1000;
01726 retvec->hciVY = interp[ivec].hciVY * 1000;
01727 retvec->hciVZ = interp[ivec].hciVZ * 1000;
01728 retvec->gciX = interp[ivec].gciX * 1000;
01729 retvec->gciY = interp[ivec].gciY * 1000;
01730 retvec->gciZ = interp[ivec].gciZ * 1000;
01731 retvec->gciVX = interp[ivec].gciVX * 1000;
01732 retvec->gciVY = interp[ivec].gciVY * 1000;
01733 retvec->gciVZ = interp[ivec].gciVZ * 1000;
01734 retvec->dsun_obs = dsun_obs[ivec] * 1000;
01735 retvec->obs_vr = hvr[ivec] * 1000;
01736 retvec->obs_vw = hvw[ivec] * 1000;
01737 retvec->obs_vn = hvn[ivec] * 1000;
01738 retvec->rsun_obs = (retvec->dsun_obs < 0.001 && retvec->dsun_obs > -0.001 ? DRMS_MISSING_DOUBLE :
01739 648000 * asin(kRSUNREF / retvec->dsun_obs) / kPI);
01740 retvec->crln_obs = l0;
01741 retvec->crlt_obs = b0;
01742 retvec->car_rot = crot;
01743
01744
01745
01746
01747
01748
01749 CreateDHashKey(dhashkey, sizeof(dhashkey), tgttimes[ivec]);
01750
01751 if ((pvindex = (int *)hcon_lookup(indexmap, dhashkey)) != NULL)
01752 {
01753 vindex = *pvindex;
01754 sprint_time(tbuf, vecs[vindex].obstime, "UTC", 0);
01755 snprintf(retvec->orb_rec, sizeof(retvec->orb_rec), "%s[%s]", srcseries, tbuf);
01756 }
01757 else
01758 {
01759 fprintf(stderr, "Unable to locate expected target time '%s' in indexmap hash.\n", dhashkey);
01760 err = kLIBASTRO_Internal;
01761 break;
01762 }
01763 }
01764 }
01765 }
01766 }
01767 else
01768 {
01769
01770
01771 for (ivec = 0; ivec < nitems; ivec++)
01772 {
01773 retvec = &((*info)[ivec]);
01774
01775 retvec->obstime = interp[ivec].obstime;
01776
01777
01778 retvec->hciVX = DRMS_MISSING_DOUBLE;
01779 retvec->hciVY = DRMS_MISSING_DOUBLE;
01780 retvec->hciVZ = DRMS_MISSING_DOUBLE;
01781 retvec->gciVX = DRMS_MISSING_DOUBLE;
01782 retvec->gciVY = DRMS_MISSING_DOUBLE;
01783 retvec->gciVZ = DRMS_MISSING_DOUBLE;
01784 retvec->obs_vw = DRMS_MISSING_DOUBLE;
01785 retvec->obs_vn = DRMS_MISSING_DOUBLE;
01786 retvec->crln_obs = DRMS_MISSING_DOUBLE;
01787 retvec->crlt_obs = DRMS_MISSING_DOUBLE;
01788 retvec->car_rot = DRMS_MISSING_INT;
01789
01790 if (drms_ismissing_time(retvec->obstime))
01791 {
01792 retvec->hciX = DRMS_MISSING_DOUBLE;
01793 retvec->hciY = DRMS_MISSING_DOUBLE;
01794 retvec->hciZ = DRMS_MISSING_DOUBLE;
01795 retvec->gciX = DRMS_MISSING_DOUBLE;
01796 retvec->gciY = DRMS_MISSING_DOUBLE;
01797 retvec->gciZ = DRMS_MISSING_DOUBLE;
01798 retvec->rsun_obs = DRMS_MISSING_DOUBLE;
01799 retvec->obs_vr = DRMS_MISSING_DOUBLE;
01800 retvec->dsun_obs = DRMS_MISSING_DOUBLE;
01801 }
01802 else
01803 {
01804
01805 retvec->hciX = interp[ivec].hciX * 1000;
01806 retvec->hciY = interp[ivec].hciY * 1000;
01807 retvec->hciZ = interp[ivec].hciZ * 1000;
01808 retvec->gciX = interp[ivec].gciX * 1000;
01809 retvec->gciY = interp[ivec].gciY * 1000;
01810 retvec->gciZ = interp[ivec].gciZ * 1000;
01811 retvec->rsun_obs = interp[ivec].rsunobs;
01812 retvec->obs_vr = interp[ivec].obsvr * 1000;
01813 retvec->dsun_obs = interp[ivec].dsunobs * 1000;
01814
01815
01816
01817
01818
01819
01820 CreateDHashKey(dhashkey, sizeof(dhashkey), tgttimes[ivec]);
01821
01822 if ((pvindex = (int *)hcon_lookup(indexmap, dhashkey)) != NULL)
01823 {
01824 vindex = *pvindex;
01825 sprint_time(tbuf, vecs[vindex].obstime, "UTC", 0);
01826 snprintf(retvec->orb_rec, sizeof(retvec->orb_rec), "%s[%s]", srcseries, tbuf);
01827 }
01828 else
01829 {
01830 fprintf(stderr, "Unable to locate expected target time '%s' in indexmap hash.\n", dhashkey);
01831 err = kLIBASTRO_Internal;
01832 break;
01833 }
01834 }
01835 }
01836 }
01837
01838 if (hb)
01839 {
01840 free(hb);
01841 }
01842
01843 if (hl)
01844 {
01845 free(hl);
01846 }
01847 }
01848 else
01849 {
01850
01851 fprintf(stderr, "Error performing interpolation.\n");
01852 err = kLIBASTRO_Interpolation;
01853 }
01854 }
01855
01856 if (dsun_obs)
01857 {
01858 free(dsun_obs);
01859 }
01860
01861 if (hvr)
01862 {
01863 free(hvr);
01864 }
01865
01866 if (hvw)
01867 {
01868 free(hvw);
01869 }
01870
01871 if (hvn)
01872 {
01873 free(hvn);
01874 }
01875
01876 if (vecs)
01877 {
01878 free(vecs);
01879 }
01880
01881 if (interp)
01882 {
01883 free(interp);
01884 }
01885
01886 if (listvecs)
01887 {
01888 list_llfree(&listvecs);
01889 }
01890
01891 if (indexmap)
01892 {
01893 hcon_destroy(&indexmap);
01894 }
01895 }
01896
01897 if (ctype == kIORBIT_CacheAction_DontCache)
01898 {
01899 DestroyCache();
01900 }
01901
01902 return err;
01903 }
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923 LIBASTRO_Error_t iorbit_getinfo(DRMS_Env_t *env,
01924 const char *srcseries,
01925 const char *optfilter,
01926 IORBIT_Alg_t alg,
01927 const double *tgttimes,
01928 int nitems,
01929 IORBIT_CacheAction_t ctype,
01930 IORBIT_Info_t **info)
01931 {
01932 return iorbit_getinfo_internal(env, srcseries, optfilter, alg, tgttimes, nitems, ctype, info, 1);
01933 }
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965 LIBASTRO_Error_t iorbit_getinfo_ext(DRMS_Env_t *env,
01966 const char *srcseries,
01967 const char *optfilter,
01968 IORBIT_Alg_t alg,
01969 const double *tgttimes,
01970 int nitems,
01971 IORBIT_CacheAction_t ctype,
01972 IORBIT_Info_t **info,
01973 HContainer_t *keymap)
01974 {
01975 if (SetUpKeymap(env, srcseries, keymap))
01976 {
01977
01978
01979 return kLIBASTRO_InvalidArgs;
01980 }
01981
01982 return iorbit_getinfo_internal(env, srcseries, optfilter, alg, tgttimes, nitems, ctype, info, 0);
01983 }
01984
01985
01986 LIBASTRO_Error_t iorbit_getSaaHlzInfo(DRMS_Env_t *env, const char *series, const double *tgttimes, int nitems, IORBIT_SaaHlzInfo_t **info)
01987 {
01988 LIBASTRO_Error_t err = kLIBASTRO_Success;
01989 int ntimes = 0;
01990 double *tgtsorted = NULL;
01991 int ipt;
01992
01993 if (info && nitems > 0)
01994 {
01995
01996 ntimes = SortTimesB(tgttimes, nitems, &tgtsorted);
01997 }
01998 else
01999 {
02000 err = kLIBASTRO_InvalidArgs;
02001 }
02002
02003 *info = NULL;
02004
02005 if (err == kLIBASTRO_Success)
02006 {
02007
02008 char stmnt[8192];
02009 DB_Binary_Result_t **res = NULL;
02010 void **values = NULL;
02011 unsigned int nargs;
02012 DB_Type_t dbtypes[2];
02013
02014 snprintf(stmnt, sizeof(stmnt), "SELECT eventtype FROM %s WHERE recnum in (SELECT max(recnum) FROM %s WHERE ? >= starttime AND ? <= stoptime GROUP BY starttime,stoptime)", series, series);
02015
02016 nargs = 2;
02017 values = calloc(1, nargs * sizeof(void *));
02018
02019 if (!values)
02020 {
02021 err = kLIBASTRO_OutOfMemory;
02022 }
02023
02024 if (!err)
02025 {
02026 values[0] = calloc(1, ntimes * sizeof(double));
02027 if (!values[0])
02028 {
02029 err = kLIBASTRO_OutOfMemory;
02030 }
02031 }
02032
02033 if (!err)
02034 {
02035 values[1] = values[0];
02036
02037
02038 dbtypes[0] = DB_DOUBLE;
02039 dbtypes[1] = DB_DOUBLE;
02040
02041 for (ipt = 0; ipt < ntimes; ipt++)
02042 {
02043 ((double *)(values[0]))[ipt] = tgtsorted[ipt];
02044 }
02045 }
02046
02047 if (!err)
02048 {
02049 if ((res = drms_query_bin_ntuple(env->session, stmnt, ntimes, nargs, dbtypes, values)) == NULL)
02050 {
02051 err = kLIBASTRO_DbStatement;
02052 }
02053 }
02054
02055 if (!err)
02056 {
02057
02058 *info = hcon_create(sizeof(HContainer_t *), IORBIT_SAAHLZINFO_TIME_KEY_LEN, (void (*)(const void *))hcon_destroy, NULL, NULL, NULL, 0);
02059 if (!*info)
02060 {
02061 err = kLIBASTRO_OutOfMemory;
02062 }
02063 }
02064
02065 if (!err)
02066 {
02067 int nrows;
02068 int irow;
02069 char eventTypeStr[IORBIT_SAAHLZINFO_KW_EVENT_TYPE_VALUE_LEN];
02070 HContainer_t *colToList = NULL;
02071 LinkedList_t *listEventType = NULL;
02072 char timeStr[IORBIT_SAAHLZINFO_TIME_KEY_LEN];
02073
02074
02075 for (ipt = 0; ipt < ntimes; ipt++)
02076 {
02077 snprintf(timeStr, sizeof(timeStr), "%lf", tgtsorted[ipt]);
02078 nrows = res[ipt]->num_rows;
02079
02080
02081
02082
02083 listEventType = list_llcreate(IORBIT_SAAHLZINFO_KW_EVENT_TYPE_VALUE_LEN, NULL);
02084
02085
02086
02087 if (!listEventType)
02088 {
02089
02090 err = kLIBASTRO_OutOfMemory;
02091 break;
02092 }
02093
02094
02095 colToList = hcon_create(sizeof(LinkedList_t *), IORBIT_SAAHLZINFO_TIME_KEY_LEN, (void (*)(const void *))list_llfree, NULL, NULL, NULL, 0);
02096 if (!colToList)
02097 {
02098
02099 err = kLIBASTRO_OutOfMemory;
02100 break;
02101 }
02102
02103
02104 for (irow = 0; irow < nrows; irow++)
02105 {
02106
02107 db_binary_field_getstr(res[ipt], irow, 0, sizeof(eventTypeStr), eventTypeStr);
02108 list_llinserttail(listEventType, eventTypeStr);
02109
02110
02111 }
02112
02113
02114 hcon_insert(colToList, IORBIT_SAAHLZINFO_KW_EVENT_TYPE, &listEventType);
02115
02116
02117 hcon_insert(*info, timeStr, &colToList);
02118 }
02119 }
02120
02121 free(values[0]);
02122 free(values);
02123 db_free_binary_result_tuple(&res, ntimes);
02124 }
02125
02126
02127 free(tgtsorted);
02128
02129 return err;
02130 }
02131
02132
02133 void iorbit_cleanup()
02134 {
02135 DestroyCache();
02136 }
02137
02138 void iorbit_cleanSaaHlzInfo(IORBIT_SaaHlzInfo_t **info)
02139 {
02140 if (info && *info)
02141 {
02142 hcon_destroy(info);
02143 }
02144 }
02145