/* ---------------------- shuddha drik panchaanga ---------------------- */ /* version 1.43 */ /* ------------------- header includes ------------------- */ #include "swephexp.h" #include "time.h" /* ------------------- function declarations ------------------- */ /* display instructions to user */ void dispinstructsfordate(void); /* convenience functions - general */ double mod360(double inbut); /* convenience functions - output */ void writetithinaama(int tithi2); void writekarananaama(int karana2); void depwarn(const char *s); /* validate and input functions */ void vinputdate(void); void safeinput(void); /* output formatting functions */ char *ppt_hm(double t); char *ppd2(int mon, int day); /* jyotisha functions */ void calcpananglesfor(double tjd2); void searchforpan(int mode, int itemnum, double startjd, char searchspace); double ayanaamshafor(double tjd2); /* main output functions */ void listsplpanchaanga(double startjd2, double endjd2); /* ------------------- variable declarations ------------------- */ char ppoutput[12]; char cvoutput[30]; char safeinputbuffer[30]; char serr[AS_MAXCH]; char chaandramaasa[80]; int jday, jmon, jyear, jhour, jmin, jsec; int planet; int tithi, vaasara, nakshatra, yoga, karana; int rtu, saayanamaasa, nirayanamaasa; int tzhour, tzmin; int repeatinput, iteration; int userinputjulianday, borderday; int depwarned; int sunatamaa0, sunatamaa1, sunatamaa2, chaandramaasatype; int32 iflag, iflgret; time_t nowval; double jut, tjd, te, x2[6]; double startjd, endjd; double xSpica[6], ayanaamsha; double grahadata[9][2], saayanasuurya; double tithiangle, nakshatraangle, yogaangle; double stithiangle, snakshatraangle, syogaangle; // to be used during search double sayanaamsha, ssunlong, smoonlong; // to be used during search double tzoffset; double low, high, border, borderoftithi; // borderoftithi used when karana is second half double amaalow, amaahigh, amaa0, amaa1, amaa2; struct tm now, nowut, ppbuffer; FILE *fp; /* ------------------- constant declarations ------------------- */ enum searchpanchoices { S_TITHI, S_NAKSHATRA, S_YOGA, S_KARANA }; double chennai[3] = {80.3, 13.1, 0.0}; char spicanaama[] = "Spica"; char *grahanaama[] = {"Bhaanu", "Soma", "Mangala", "Budha", "Guru", "Shukra", "Shani"}; char *tithinaama[] = { "Pratham", "Dvitii", "Tritii", "Chatur", "Pancha", "Shash", "Sapta", "Ashta", "Nava", "Dasha", "Ekaada", "Dvaada", "Trayoda", "Chaturda" }; // puurnimaa and amaavaasyaa will be handled separately char *nakshatranaama[] = { "Ashvinii", "Bharanii", "Kritti", "Rohinii", "Mriga", "Aardraa", "Punar", "Pushya", "Aashre", "Maghaa", "P Phal", "U Phal", "Hasta", "Chitraa", "Svaatii", "Vishaa", "Anuraa", "Jyesh", "Muula", "P Ashaa", "U Ashaa", "Shravana", "Shravish", "Shata", "P Prosh", "U Prosh", "Revatii" }; char *yoganaama[] = { "Vishkam", "Priiti", "Aayush", "Saubhaa", "Shobhana", "Atiganda", "Sukarman", "Dhriti", "Shuula", "Ganda", "Vriddhi", "Dhruva", "Vyaaghaa", "Harshana", "Vajra", "Siddhi", "Vyatii", "Varigha", "Parigha", "Shiva", "Siddha", "Saadhya", "Shubha", "Shubhra", "Braahma", "Maahen", "Vaidhri" }; char *karananaama[] = { "Bava", "Baalava", "Kaulava", "Taitila", "Garajaa", "Vanijaa", "Bhadraa" }; // sthira karana-s will be handled separately double arcmin800 = 360.0 / 27.0; /* ------------------- main function ------------------- */ int main(int argc, char *argv[]) { swe_set_ephe_path("."); iflag = SEFLG_SPEED; userinputjulianday = 0; depwarned = 0; tzoffset = 0; printf("\n"); /* testing dependency files */ if ((fp = fopen("fixstars.cat", "r")) == NULL) depwarn("fixstars.cat"); else fclose(fp); if ((fp = fopen( "sepl_18.se1", "r")) == NULL) depwarn( "sepl_18.se1"); else fclose(fp); if ((fp = fopen( "semo_18.se1", "r")) == NULL) depwarn( "semo_18.se1"); else fclose(fp); /* ayanaamshafor(2451545.0); if (iflgret < 0) depwarn("fixstars.cat"); iflgret = swe_calc(2451545.0, 0, iflag, x2, serr); // sun if ((iflgret < 0) || (iflgret != iflag)) depwarn("sepl_18.se1"); iflgret = swe_calc(2451545.0, 1, iflag, x2, serr); // moon if ((iflgret < 0) || (iflgret != iflag)) depwarn("semo_18.se1"); */ if (depwarned) printf("\n"); /* processing arguments */ argc--; if (argc == 0) // no commandline arguments { printf("Please provide the start and end Gregorian dates.\n"); dispinstructsfordate(); tzoffset = 5.5 / 24.0; printf("Please enter the start date.\n"); vinputdate(); startjd = swe_julday(jyear,jmon,jday,jut,SE_GREG_CAL) - tzoffset; printf("Please enter the end date.\n"); do { repeatinput = FALSE; vinputdate(); endjd = swe_julday(jyear,jmon,jday,jut,SE_GREG_CAL) - tzoffset; if ((int) endjd <= (int) startjd) repeatinput = TRUE; if (repeatinput) printf("Please enter an end date later than the start date.\n"); } while (repeatinput); listsplpanchaanga(startjd, endjd); } else // too many parameters { printf ("Too many parameters.\n"); } printf("\nWritten special panchaanga for given date range for Chennai to monthpan.txt\n\n"); return 1; } /* display instructions to user */ void dispinstructsfordate(void) { printf("Years must be in the range 1800 to 2399 CCE (\"AD\"). Two-digit years are not accepted.\n"); printf("The timezone must be specified in terms of the UTC offset, positive east of Greenwich.\n\n"); } /* convenience functions - general */ double mod360(double inbut) { if (inbut >= 360.0) return (inbut - 360.0); if (inbut < 0.0) return (inbut + 360.0); return inbut; } /* convenience functions - output */ void writetithinaama(int tithi2) { tithi2 %= 30; if (tithi2 == 14) fprintf(fp, " Puurni "); else if (tithi2 == 29) fprintf(fp, " Amaa "); else fprintf(fp, "%8s ", tithinaama[(tithi2 > 14) ? (tithi2 - 15) : tithi2]); } void writekarananaama(int karana2) { karana2 %= 60; switch(karana2) { case 0: fprintf(fp, " Kimstu "); break; case 57: fprintf(fp, "Shakuni "); break; case 58: fprintf(fp, "Chatush "); break; case 59: fprintf(fp, "Naagava "); break; default: fprintf(fp, "%7s ", karananaama[(karana2 - 1) % 7]); break; } } void depwarn(const char *s) { printf("WARNING: %12s not found. Internal medium-accuracy formulae will be used.\n", s); // to change to "or corrupted" when the corruption checking is debugged depwarned = 1; } /* validate and input functions */ void vinputdate(void) { do { repeatinput = FALSE; printf("Date as YYYY-MM-DD : "); safeinput(); if (sscanf(safeinputbuffer, "%d-%d-%d", &jyear, &jmon, &jday) < 1) repeatinput = TRUE; if (swe_date_conversion(jyear, jmon, jday, 0.0, 'g', &tjd) == ERR) repeatinput = TRUE; if (jyear < 1800 || jyear > 2399) repeatinput = TRUE; if (repeatinput) printf ("Please enter a valid date.\n"); } while (repeatinput); } void safeinput(void) { fgets(safeinputbuffer, 30, stdin); } /* formatting functions */ char *ppt_hm(double t) // pretty print time -- no seconds { ppbuffer.tm_mday = 1; // since it's the only member without zero value ppbuffer.tm_hour = (int) t; t -= ppbuffer.tm_hour; t *= 60.0; ppbuffer.tm_min = (int) t; strftime (ppoutput, 6, "%H:%M", &ppbuffer); return ppoutput; } char *ppd2(int mon, int day) // pretty print date { ppbuffer.tm_mon = mon - 1; ppbuffer.tm_mday = day; strftime (ppoutput, 11, "%b-%d", &ppbuffer); return ppoutput; } /* jyotisha functions */ void calcpananglesfor(double tjd2) { /* calculate ephemeris time in julian days */ te = tjd2 + swe_deltat(tjd2); /* calculate ayanaamsha */ sayanaamsha = ayanaamshafor(te); /* calculate sun and moon */ swe_calc(te, 0, iflag, x2, serr); // sun ssunlong = mod360(x2[0] - sayanaamsha); swe_calc(te, 1, iflag, x2, serr); // moon smoonlong = mod360(x2[0] - sayanaamsha); /* calculate the tithi, nakshatra and yoga angles for search */ stithiangle = mod360(smoonlong - ssunlong); // lunar minus solar longitude snakshatraangle = smoonlong; // lunar longitude syogaangle = mod360(smoonlong + ssunlong); // lunar plus solar longitude } void searchforpan(int mode, int itemnum, double startjd, char searchspace) { low = startjd; switch (searchspace) { case 'h': high = low + 0.5; break; case 'f': high = low + 1.0; break; case 'x': high = low + 1.5; break; } for (iteration = 1; iteration < 26; iteration++) { border = (low + high) / 2.0; calcpananglesfor(border); switch (mode) { case S_TITHI: if (itemnum > 29) itemnum -= 30; // needed because we search for tithi + 2 etc if (itemnum == 0) { if (stithiangle > 330.0) low = border; if (stithiangle < 30.0) high = border; } else { if (stithiangle < (itemnum * 12.0)) low = border; else high = border; } break; case S_NAKSHATRA: if (itemnum > 26) itemnum -= 27; // needed because we search for nakshatra + 2 etc if (itemnum == 0) { if (snakshatraangle > 330.0) low = border; if (snakshatraangle < 30.0) high = border; } else { if (snakshatraangle < (itemnum * arcmin800)) low = border; else high = border; } break; case S_YOGA: if (itemnum > 26) itemnum -= 27; // needed because we search for yoga + 2 etc if (itemnum == 0) { if (syogaangle > 330.0) low = border; if (syogaangle < 30.0) high = border; } else { if (syogaangle < (itemnum * arcmin800)) low = border; else high = border; } break; case S_KARANA: if (itemnum > 59) itemnum -= 60; // needed because we search for karana + 2 etc if (itemnum == 0) { if (stithiangle > 330.0) low = border; if (stithiangle < 30.0) high = border; } else { if (stithiangle < (itemnum * 6.0)) low = border; else high = border; } break; } } } double ayanaamshafor(double te2) { iflgret = swe_fixstar(spicanaama, te2, iflag, xSpica, serr); if (iflgret >= 0) return (xSpica[0] - 180.0); // < 0 -> file not found or corrupted /* the following section is evaluated only if the fixstars.cat file is not found or is corrupted */ double t; double ra_h, ra_m, ra_s, ra; double de_d, de_m, de_s, de; double ra_pm, de_pm; double parallax, r, radv; double sinra, cosra; double sinde, cosde; double x, y, z; double delx, dely, delz; double zeta, zee, theta; double cosraz; double sinth, costh; double A, B, C; double ep; double lambda, ayana; double obli_nut[6]; t = te2 - 2451545.0; // days since J2000.0 t /= 365.25; // convert to years /* spica value initialization */ /* 1. x-y position */ ra_h = 13.0; ra_m = 25.0; ra_s = 11.5793; ra = (ra_h + ra_m / 60.0 + ra_s / 3600.0) * 15.0; // convert to degrees ra *= DEGTORAD; // convert to radians; de_d = -11.0; de_m = -9.0; de_s = -40.759; de = de_d + de_m / 60.0 + de_s / 3600.0; // convert to degrees de *= DEGTORAD; // convert to radians /* 2. x-y motion */ ra_pm = -42.50; // mas/yr de_pm = -31.73; // mas/yr ra_pm /= (3600.0 * 1000.0); // convert to degrees per year; de_pm /= (3600.0 * 1000.0); ra_pm *= DEGTORAD; // convert to radians per year de_pm *= DEGTORAD; /* 3. z position and motion */ parallax = 12.44; // milliarcseconds parallax /= 1000.0; // convert to arcseconds r = 1 / parallax; // distance in parsecs radv = 1.0; // km/s radv /= 977792.0; // convert to parsecs per year #if 0 /* simple proper motion */ ra += ra_pm * t; de += de_pm * t; #endif /* rigorous proper motion */ sinra = sin(ra); // convenience cosra = cos(ra); sinde = sin(de); cosde = cos(de); x = r * cosde * cosra; y = r * cosde * sinra; z = r * sinde; delx = (x / r) * radv - z * de_pm * cosra - y * ra_pm; dely = (y / r) * radv - z * de_pm * sinra + x * ra_pm; delz = (z / r) * radv + r * de_pm * cosde; x += t * delx; y += t * dely; z += t * delz; ra = atan2(y, x); de = atan2(z, sqrt(x * x + y * y)); /* precession */ t /= 100.0; // convert to centuries zeta = t * (2306.2181 + t * (0.30188 + t * 0.018998)); zee = t * (2306.2181 + t * (1.09468 + t * 0.018203)); theta = t * (2004.3109 + t * (0.42665 + t * 0.041833)); zeta /= 3600.0; // to degrees zee /= 3600.0; theta /= 3600.0; zeta *= DEGTORAD; // to radians zee *= DEGTORAD; theta *= DEGTORAD; cosraz = cos(ra + zeta); sinth = sin(theta); costh = cos(theta); sinde = sin(de); // recalculation for changed de value cosde = cos(de); A = cosde * sin(ra + zeta); B = cosde * cosraz * costh - sinth * sinde; C = cosde * cosraz * sinth + costh * sinde; ra = atan2(A, B) + zee; de = asin(C); /* find obliquity and nutation in longitude */ swe_calc(te2, SE_ECL_NUT, 0, obli_nut, serr); ep = obli_nut[0]; // ep = 23.0 + 26.0 / 60.0 + 21.448 / 3600.0; // J2000 ep *= DEGTORAD; /* find ecliptic longitude */ lambda = atan2(sin(ra) * cos(ep) + tan(de) * sin(ep), cos(ra)); lambda /= DEGTORAD; lambda += obli_nut[2]; /* find and return ayanaamsha */ ayana = lambda - 180.0; if (ayana < 0.0) ayana += 360.0; return ayana; } /* main output function */ void listsplpanchaanga(double startjd2, double endjd2) { fp = fopen("monthpan.txt", "w"); int secondtithi, secondnakshatra, secondyoga, thirdkarana; char bsecondtithi[10], bsecondnakshatra[10], bsecondyoga[10], bthirdkarana[10]; int extraexists; int endtithi, endnakshatra, endyoga, endkarana; int mendtithi, mendnakshatra, mendyoga, mendkarana; double prev_sunset, this_sunrise, this_sunset, this_braahma, this_noon; /* mend are modified end values use to prevent discontinuity at 0; if (start)tithi == 29 and endtithi == 0, endtithi would not be identified as (start)tithi + 1 similarly for other cases we cannot manipulate the end___ variables themselves since we need them to assign their values to the start___ variables for the next day */ calcpananglesfor(startjd2); tithi = stithiangle / 12.0; // prathamaa == 0 nakshatra = snakshatraangle / arcmin800; // ashvinii == 0 yoga = syogaangle / arcmin800; // vishkambha == 0 karana = stithiangle / 6.0; // kimstughna == 0 swe_rise_trans(startjd2 - 1, SE_SUN, NULL, SEFLG_SWIEPH, SE_CALC_SET + SE_BIT_DISC_CENTER + SE_BIT_NO_REFRACTION, chennai, 0, 25, &prev_sunset, serr); //fprintf(fp, "debug: first prev_sunset %f \n", prev_sunset); for (tjd = startjd2; tjd <= endjd2; tjd++) { extraexists = 0; secondtithi = secondnakshatra = secondyoga = thirdkarana = 300; // an illegal value for all these swe_revjul (tjd + tzoffset, SE_GREG_CAL, &jyear, &jmon, &jday, &jut); fprintf(fp, "%6s | ", ppd2(jmon, jday)); swe_rise_trans(tjd, SE_SUN, NULL, SEFLG_SWIEPH, SE_CALC_RISE + SE_BIT_DISC_CENTER + SE_BIT_NO_REFRACTION, chennai, 0, 25, &this_sunrise, serr); swe_rise_trans(tjd, SE_SUN, NULL, SEFLG_SWIEPH, SE_CALC_SET + SE_BIT_DISC_CENTER + SE_BIT_NO_REFRACTION, chennai, 0, 25, &this_sunset, serr); this_braahma = this_sunrise - (this_sunrise - prev_sunset) / 5; this_noon = (this_sunrise + this_sunset) / 2; fprintf(fp, "%5s ", ppt_hm((this_braahma - tjd) * 24.0)); fprintf(fp, "%5s ", ppt_hm((this_sunrise - tjd) * 24.0)); fprintf(fp, "%5s ", ppt_hm((this_noon - tjd) * 24.0)); fprintf(fp, "%5s | ", ppt_hm((this_sunset - tjd) * 24.0)); calcpananglesfor(tjd + 1); vaasara = fmod(tjd + tzoffset + 1.5, 7); mendtithi = endtithi = stithiangle / 12.0; mendnakshatra = endnakshatra = snakshatraangle / arcmin800; mendyoga = endyoga = syogaangle / arcmin800; mendkarana = endkarana = stithiangle / 6.0; if (tithi != 0 && endtithi == 0) mendtithi += 30; if (tithi == 29 && endtithi == 1) mendtithi += 30; if (nakshatra != 0 && endnakshatra == 0) mendnakshatra += 27; if (nakshatra == 26 && endnakshatra == 1) mendnakshatra += 27; if (yoga != 0 && endyoga == 0) mendyoga += 27; if (yoga == 26 && endyoga == 1) mendyoga += 27; if (karana != 0 && endkarana == 0) mendkarana += 60; if (karana != 0 && endkarana == 1) mendkarana += 60; if (karana == 59 && endkarana == 2) mendkarana += 60; /* karana can go from 59 to 0, 58 to 0, 57 to 0 59 to 1, 58 to 1 59 to 2 it is safe to test for karana != 0 as a shortcut to (karana == 58 || karana == 59) since karana == 1 && endkarana == 1 is *never* possible otoh tithi == 1 && endtithi == 1 is possible, so tithi != 0 would test false positive for tithi == 1 whereas it should evaluate only for tithi == 29 so we use safely tithi == 29 besides, since only one non-zero tithi value is possible for endtithi == 1, a shortcut is not required and regarding the mend___ += statements, i opted for += instead of direct assignment for the logic to be clear and remember that the mend___ values are assigned simultaneously with the end___ values, else += would not work as expected to produce 30 for 0 or 31 for 1 etc */ if ((mendtithi == tithi + 2) || (mendnakshatra == nakshatra + 2) || (mendyoga == yoga + 2) || (mendkarana == karana + 3)) extraexists = 1; if (tithi < 15) fprintf(fp, "Sh "); else fprintf(fp, "Kr "); writetithinaama(tithi); if (mendtithi == tithi + 2) { searchforpan(S_TITHI, tithi + 2, tjd, 'f'); // search for *start* of tithi + 2 secondtithi = tithi + 1; // we need to print name of tithi + 1 strcpy(bsecondtithi, ppt_hm((border - tjd) * 24.0)); } if (mendtithi > tithi) // tests for tithi + 1 and tithi + 2 { searchforpan(S_TITHI, tithi + 1, tjd, 'f'); fprintf(fp, "%5s | ", ppt_hm((border - tjd) * 24.0)); } if (mendtithi == tithi) fprintf(fp, " / | "); printf("debug: vaasara = %d, graha = %7s\n", vaasara, grahanaama[vaasara]); fprintf(fp, "%7s | ", grahanaama[vaasara]); fprintf(fp, "%8s ", nakshatranaama[nakshatra]); if (mendnakshatra == nakshatra + 2) { searchforpan(S_NAKSHATRA, nakshatra + 2, tjd, 'f'); // search for *start* of nakshatra + 2 secondnakshatra = nakshatra + 1; // we need to print name of nakshatra + 1 strcpy(bsecondnakshatra, ppt_hm((border - tjd) * 24.0)); } if (mendnakshatra > nakshatra) // tests for nakshatra + 1 and nakshatra + 2 { searchforpan(S_NAKSHATRA, nakshatra + 1, tjd, 'f'); fprintf(fp, "%5s | ", ppt_hm((border - tjd) * 24.0)); } if (mendnakshatra == nakshatra) fprintf(fp, " / | "); fprintf(fp, "%8s ", yoganaama[yoga]); if (mendyoga == yoga + 2) { searchforpan(S_YOGA, yoga + 2, tjd, 'f'); // search for *start* of yoga + 2 secondyoga = yoga + 1; // we need to print name of yoga + 1 strcpy(bsecondyoga, ppt_hm((border - tjd) * 24.0)); } if (mendyoga > yoga) // tests for yoga + 1 and yoga + 2 { searchforpan(S_YOGA, yoga + 1, tjd, 'f'); fprintf(fp, "%5s | ", ppt_hm((border - tjd) * 24.0)); } if (mendyoga == yoga) fprintf(fp, " / | "); writekarananaama(karana); searchforpan(S_KARANA, karana + 1, tjd, 'f'); // max karana size is larger than half-day, so 'f' fprintf(fp, "%5s ", ppt_hm((border - tjd) * 24.0)); writekarananaama(karana + 1); if (mendkarana == karana + 3) { searchforpan(S_KARANA, karana + 3, tjd, 'f'); // search for *start* of karana + 3 thirdkarana = karana + 2; // we need to print name of karana + 2 strcpy(bthirdkarana, ppt_hm((border - tjd) * 24.0)); } if (mendkarana > karana + 1) // tests for karana + 2 and karana + 3 { searchforpan(S_KARANA, karana + 2, tjd, 'f'); // search for *start* of karana + 2 fprintf(fp, "%5s", ppt_hm((border - tjd) * 24.0)); } if (mendkarana == karana + 1) fprintf(fp, " /"); fprintf(fp, "\n"); if (extraexists) { fprintf(fp, " | | "); // date and times if (secondtithi == 300) fprintf(fp, " - - - | "); // paksha and tithi else { if (secondtithi < 15) fprintf(fp, "Sh "); else fprintf(fp, "Kr "); writetithinaama(secondtithi % 30); fprintf(fp, "%5s | ", bsecondtithi); } fprintf(fp, " - | "); // vaasara if (secondnakshatra == 300) fprintf(fp, " - - | "); // nakshatra else { fprintf(fp, "%8s ", nakshatranaama[secondnakshatra % 27]); fprintf(fp, "%5s | ", bsecondnakshatra); } if (secondyoga == 300) fprintf(fp, " - - | "); // yoga else { fprintf(fp, "%8s ", yoganaama[secondyoga % 27]); fprintf(fp, "%5s | ", bsecondyoga); } fprintf(fp, " - - "); // first karana if (thirdkarana == 300) fprintf(fp, " - -"); // second karana else { writekarananaama(thirdkarana % 60); fprintf(fp, "%5s", bthirdkarana); // two spaces just for consistency } fprintf(fp, "\n"); } tithi = endtithi; nakshatra = endnakshatra; yoga = endyoga; karana = endkarana; prev_sunset = this_sunset; } fclose(fp); }