#include #include #include #include #include #include #include "sgdp4h.h" #define LIM 384 #define D2R M_PI/180.0 #define R2D 180.0/M_PI #define XKMPAU 149597879.691 // AU in km struct map { int site_id; double mjd; float saltmin,alt; char nfd[LIM],observer[32],datadir[LIM]; double lat,lng; float length; } m; void allnight(void); void sunpos_xyz(double,xyz_t *,double *,double *); double modulo(double,double); void equatorial2horizontal(double,double,double,double *,double *); void mjd2date(double mjd,char *date); double gmst(double mjd); void nfd_now(char *s); double nfd2mjd(char *date); void get_site(int site_id); double date2mjd(int year,int month,double day); void usage(void); int main(int argc,char *argv[]) { int arg=0; char *env; // Default settings strcpy(m.observer,"Unknown"); m.site_id=0; m.mjd=-1.0; m.saltmin=-6.0; m.alt=0.0; m.lat=0.0; m.lng=0.0; // Get default site env=getenv("ST_DATADIR"); if (env!=NULL) { strcpy(m.datadir,env); } else { printf("ST_DATADIR environment variable not found.\n"); } env=getenv("ST_COSPAR"); if (env!=NULL) { get_site(atoi(env)); } else { printf("ST_COSPAR environment variable not found.\n"); } // Get current time nfd_now(m.nfd); m.mjd=nfd2mjd(m.nfd); // Decode options while ((arg=getopt(argc,argv,"t:s:S:h"))!=-1) { switch (arg) { case 't': strcpy(m.nfd,optarg); m.mjd=nfd2mjd(m.nfd); break; case 'S': m.saltmin=atof(optarg); break; case 's': get_site(atoi(optarg)); break; case 'h': usage(); return 0; break; default: usage(); return 0; } } // Compute set/rise times of sun allnight(); return 0; } // Usage void usage(void) { printf("allnight t:s:S:\n\n"); printf("t date/time (yyyy-mm-ddThh:mm:ss.sss) [default: now]\n"); printf("S Minimum sun altitude\n"); printf("s site (COSPAR)\n"); return; } // Convert equatorial into horizontal coordinates void equatorial2horizontal(double mjd,double ra,double de,double *azi,double *alt) { double h; h=gmst(mjd)+m.lng-ra; *azi=modulo(atan2(sin(h*D2R),cos(h*D2R)*sin(m.lat*D2R)-tan(de*D2R)*cos(m.lat*D2R))*R2D,360.0); *alt=asin(sin(m.lat*D2R)*sin(de*D2R)+cos(m.lat*D2R)*cos(de*D2R)*cos(h*D2R))*R2D; return; } // Return x modulo y [0,y) double modulo(double x,double y) { x=fmod(x,y); if (x<0.0) x+=y; return x; } // Solar position void sunpos_xyz(double mjd,xyz_t *pos,double *ra,double *de) { double jd,t,l0,m,e,c,r; double n,s,ecl; jd=mjd+2400000.5; t=(jd-2451545.0)/36525.0; l0=modulo(280.46646+t*(36000.76983+t*0.0003032),360.0)*D2R; m=modulo(357.52911+t*(35999.05029-t*0.0001537),360.0)*D2R; e=0.016708634+t*(-0.000042037-t*0.0000001267); c=(1.914602+t*(-0.004817-t*0.000014))*sin(m)*D2R; c+=(0.019993-0.000101*t)*sin(2.0*m)*D2R; c+=0.000289*sin(3.0*m)*D2R; r=1.000001018*(1.0-e*e)/(1.0+e*cos(m+c)); n=modulo(125.04-1934.136*t,360.0)*D2R; s=l0+c+(-0.00569-0.00478*sin(n))*D2R; ecl=(23.43929111+(-46.8150*t-0.00059*t*t+0.001813*t*t*t)/3600.0+0.00256*cos(n))*D2R; *ra=atan2(cos(ecl)*sin(s),cos(s))*R2D; *de=asin(sin(ecl)*sin(s))*R2D; pos->x=r*cos(*de*D2R)*cos(*ra*D2R)*XKMPAU; pos->y=r*cos(*de*D2R)*sin(*ra*D2R)*XKMPAU; pos->z=r*sin(*de*D2R)*XKMPAU; return; } void allnight(void) { int flag; xyz_t sunpos; double ra,de,azi,alt,alt0; double mjd,mjdrise=-1.0,mjdset=-1.0; char nfd[32]; // Find solar altitude at reference time sunpos_xyz(m.mjd,&sunpos,&ra,&de); equatorial2horizontal(m.mjd,ra,de,&azi,&alt); // Sun below limit, find rise, then set if (altm.saltmin && alt0<=m.saltmin) mjdrise=mjd; } if (flag==0) flag=1; alt0=alt; } for (flag=0,mjd=m.mjd-0.5;mjd=m.saltmin) mjdset=mjd; } if (flag==0) flag=1; alt0=alt; } // Sun above limit, find set, and rise } else { for (flag=0,mjd=m.mjd;mjdm.saltmin && alt0<=m.saltmin) mjdrise=mjd; if (alt=m.saltmin) mjdset=mjd; } if (flag==0) flag=1; alt0=alt; } } m.mjd=mjdset; mjd2date(m.mjd,m.nfd); mjd2date(mjdrise,nfd); printf("%s %s\n",m.nfd,nfd); return; } // Compute Date from Julian Day void mjd2date(double mjd,char *date) { double f,jd,dday; int z,alpha,a,b,c,d,e; int year,month,day,hour,min; float sec,x; jd=mjd+2400000.5; jd+=0.5; z=floor(jd); f=fmod(jd,1.); if (z<2299161) a=z; else { alpha=floor((z-1867216.25)/36524.25); a=z+1+alpha-floor(alpha/4.); } b=a+1524; c=floor((b-122.1)/365.25); d=floor(365.25*c); e=floor((b-d)/30.6001); dday=b-d-floor(30.6001*e)+f; if (e<14) month=e-1; else month=e-13; if (month>2) year=c-4716; else year=c-4715; day=(int) floor(dday); x=24.0*(dday-day); x=3600.*fabs(x)+0.0001; sec=fmod(x,60.); x=(x-sec)/60.; min=fmod(x,60.); x=(x-min)/60.; hour=x; sec=floor(1000.0*sec)/1000.0; sprintf(date,"%04d-%02d-%02dT%02d:%02d:%02.0f",year,month,day,hour,min,sec); return; } // Greenwich Mean Sidereal Time double gmst(double mjd) { double t,gmst; t=(mjd-51544.5)/36525.0; gmst=modulo(280.46061837+360.98564736629*(mjd-51544.5)+t*t*(0.000387933-t/38710000),360.0); return gmst; } // Present nfd void nfd_now(char *s) { time_t rawtime; struct tm *ptm; // Get UTC time time(&rawtime); ptm=gmtime(&rawtime); sprintf(s,"%04d-%02d-%02dT%02d:%02d:%02d",ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec); return; } // nfd2mjd double nfd2mjd(char *date) { int year,month,day,hour,min,sec; double mjd,dday; sscanf(date,"%04d-%02d-%02dT%02d:%02d:%02d",&year,&month,&day,&hour,&min,&sec); dday=day+hour/24.0+min/1440.0+sec/86400.0; mjd=date2mjd(year,month,dday); return mjd; } // Compute Julian Day from Date double date2mjd(int year,int month,double day) { int a,b; double jd; if (month<3) { year--; month+=12; } a=floor(year/100.); b=2.-a+floor(a/4.); if (year<1582) b=0; if (year==1582 && month<10) b=0; if (year==1582 && month==10 && day<=4) b=0; jd=floor(365.25*(year+4716))+floor(30.6001*(month+1))+day+b-1524.5; return jd-2400000.5; } // Get observing site void get_site(int site_id) { int i=0; char line[LIM]; FILE *file; int id; double lat,lng; float alt; char abbrev[3],observer[64],filename[LIM]; sprintf(filename,"%s/data/sites.txt",m.datadir); file=fopen(filename,"r"); if (file==NULL) { printf("File with site information not found!\n"); return; } while (fgets(line,LIM,file)!=NULL) { // Skip if (strstr(line,"#")!=NULL) continue; // Strip newline line[strlen(line)-1]='\0'; // Read data sscanf(line,"%4d %2s %lf %lf %f", &id,abbrev,&lat,&lng,&alt); strcpy(observer,line+38); // Change to km alt/=1000.0; if (id==site_id) { m.lat=lat; m.lng=lng; m.alt=alt; m.site_id=id; strcpy(m.observer,observer); } } fclose(file); return; }