File: unit_hjd.pas

package info (click to toggle)
astap 2024.11.13-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,032 kB
  • sloc: pascal: 49,240; sh: 205; makefile: 5
file content (392 lines) | stat: -rw-r--r-- 18,655 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
unit unit_hjd;
{ Converts Julian day to Heliocentric Julian Day. Difference is maximum +- 500 sec / 8.3 minutes }

{Copyright (C) 2017, 2024 by Han Kleijn, www.hnsky.org
 email: han.k.. at...hnsky.org

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.   }

{$mode delphi}

interface

uses
  Classes, SysUtils, math,  LazSysUtils, {nowUtc}
  astap_main {for theader};

var
  ra_mean : double=0;
  dec_mean: double=0;
  site_lat_radians, site_long_radians,wtime2actual : double;


function calc_jd_now: double;  {get julian day for now}

function JD_to_HJD(jd,ra_object,dec_object: double): double;{conversion JD to HJD}  {see https://en.wikipedia.org/wiki/Heliocentric_Julian_Day}
procedure equ_gal(ra,dec:double;out l,b: double);{equatorial to galactic coordinates}
function airmass_calc(h: double): double; // where h is apparent altitude in degrees.
function atmospheric_absorption(airmass: double):double;{magnitudes}
procedure calculate_az_alt(calc_mode : integer;head: Theader; out az,alt : double);{calculate az, alt. Move try to use header values else force calculation. Unit degrees}
procedure altitude_and_refraction(lat,long,julian,temperature,pressure,ra3,dec3: double; out az,alt  : double);{altitude calculation and correction ra, dec for refraction}
function calculate_az_alt_basic(ra,dec : double; out az,alt : double): boolean;{calculate azimuth, altitude and  initialize wtime2actual/sidereal time if site_lat_radians>999. For mouse pointer}

procedure polar2(x,y,z:double;out r,theta,phi:double);
function get_lat_long(out site_lat_radians, site_long_radians : double): boolean;//retrieve latitude and longitude
procedure az_ra(az,alt,lat,long,t:double;out ra,dcr: double);{conversion az,alt to ra,dec}
procedure ra_az(ra,de,LAT,LONG,t:double;out azimuth2,altitude2: double);{conversion ra & dec to altitude,azimuth}

implementation
uses
  unit_stack, unit_ephemerides,unit_asteroid, unit_aberration;


function calc_jd_now: double; {get julian day for now}
var
  yy,mm,dd :word;
  hour,min, ss,ms: Word;
  dt         :tdatetime;

begin
  dt:=LazSysUtils.NowUTC;
  DeCodeDate(dt,YY,MM,DD);
  DecodeTime(dt,hour,min,ss,ms);
  result:=julian_calc(yy,mm,dd,hour,min,ss+ms/1000);{calculate julian day}
end;



{ sun:      low precision solar coordinates (approx. 1')               }
{           jd : julian day                                            }
{           ra : right ascension (in radians; equinox of date)         }
{           dec: declination (in radians; equinox of date)             }
{           Factors from "Astronomy on the personal computer"          }
procedure sun(jd:real; var ra,dec: double); {jd  var ra 0..2*pi, dec [0..pi/2] of Sun equinox of date}
  const
    cos_ecl=cos(23.43929111*pi/180);{obliquity of ecliptic}
    sin_ecl=sin(23.43929111*pi/180);{obliquity of ecliptic}
  var
    angle,l,m,dl,sin_l,cos_l,y,z,rho,t: double;

  begin
    t:=(jd-2451545)/36525; {time in julian centuries since j2000 }
    m  := 2*pi*frac(0.993133+99.997361*t);
    dl:= 6893.0*sin(m)+72.0*sin(2*m);
    angle:=frac(0.7859453 + m/(2*pi) + (6191.2*t+dl)/1296e3);{orbit position}
    if angle<0 then angle:=angle+1;   {frac(-1.1) is -0.1, should become 0.9}
    l := 2*pi*angle; {orbit position in radians}
    sincos(l,sin_l,cos_l);
    y:=cos_ecl*sin_l;{convert helio to geocentric coordinates}
    z:=sin_ecl*sin_l;
    rho:=sqrt(1.0-z*z);
    dec := arctan(z/rho);
    ra  := 2*arctan(y/(cos_l+rho));
    if (ra<0) then ra:=ra+(2*pi);
  end;


//procedure precession(jd, ra1,dec1 : double; var ra2,dec2 : double); {precession correction,  simple formula, new Meeus chapter precession}
//var
//  t,dra,ddec,sin_ra1,cos_ra1,m,n,n2  : double;

//begin
//  t:=(jd-2451545)/36525; {time in julian centuries since j2000 }
//  m:=3.075+0.00186*t;{seconds}
//  n:=1.33621-0.00057*t; {seconds}
//  n2:=20.043-0.0085*t;{arcsec}
//  sincos(ra1,sin_ra1,cos_ra1);
//  dra:=(m + n *sin_ra1*tan(dec1))*pi/(3600*12);{yearly ra drift in radians}
//  ddec:=n2*cos_ra1*pi/(3600*180); {yearly dec drift in radians}
//  ra2:=ra1+(dra*t*100);{multiply with number of years is t*100}
//  dec2:=dec1+(ddec*t*100);
//end;


function JD_to_HJD(jd,ra_object,dec_object: double): double;{conversion Julian Day to Heliocentric Julian Day}
var                                                         {see https://en.wikipedia.org/wiki/Heliocentric_Julian_Day}
  ra_sun, dec_sun : double;
  sin_dec_object,cos_dec_object,sin_dec_sun,cos_dec_sun : double;
begin
  sun(jd,ra_sun,dec_sun);{get sun position in equinox of date coordinates}
  precession3(jd, 2451545 {J2000},ra_sun,dec_sun); {precession}
  sincos(dec_object,sin_dec_object,cos_dec_object);
  sincos(dec_sun,sin_dec_sun,cos_dec_sun);

  result:=jd - 500{sec}*(1/(24*3600))*(sin_dec_object* sin_dec_sun + cos_dec_object * cos_dec_sun * cos(ra_object -  ra_sun));  {assume 500 sec travel time Sun- Earth}
end;


procedure equ_gal(ra,dec:double;out l,b: double);{equatorial to galactic coordinates}
const
  {North_galactic pole (J2000)}
  pole_ra : double = (12+51/60+26.27549/3600)*pi/12; {12h51m26.27549    https://www.aanda.org/articles/aa/pdf/2011/02/aa14961-10.pdf }
  pole_dec: double = (27+7/60+41.7043/3600)*pi/180; {+27◦07′41.7043′′}
  posangle: double = (122.93191857-90)*pi/180; {122.93191857◦}

// Converting between galactic to equatorial coordinates
// The galactic north pole is at RA = 12:51.4, Dec = +27:07 (2000.0),
// the galactic center at RA = 17:45.6, Dec = -28:56 (2000.0).
// The inclination of the galactic equator to the celestial equator is thus 62.9°.
// The intersection, or node line, of the two equators is at
// RA = 282.25°, Dec = 0:00 (2000.0), and at l = 33°, b=0.
var
  sin_b, cos_b, sin_pole_dec, cos_pole_dec :double;
begin
  sincos(pole_dec,sin_pole_dec, cos_pole_dec);
  b:=arcsin(cos(dec)*cos_pole_dec*cos(ra - pole_ra) + sin(dec)*sin_pole_dec);
  sincos(b,sin_b, cos_b);
  l:=arctan2(  (sin(dec) - sin_b *sin_pole_dec ) , (cos(dec)*cos_pole_dec*sin(ra - pole_ra)) )  + posangle;
end;


//function altitude(ra3,dec3 {2000},lat,long,julian:double):double;{conversion ra & dec to altitude only. This routine is created for speed, only the altitude is calculated}
//{input RA [0..2pi], DEC [-pi/2..+pi/2],lat[-pi/2..pi/2], long[-pi..pi] West positive, East negative !!,time[0..2*pi]}
//var t5,wtime2actual : double;
//    sin_lat,cos_lat,sin_dec,cos_dec:double;
//const
//  siderealtime2000=(280.46061837)*pi/180;{[radians],  90 degrees shifted sidereal time at 2000 jan 1.5 UT (12 hours) =Jd 2451545 at meridian greenwich, see new meeus 11.4}
//  earth_angular_velocity = pi*2*1.00273790935; {about(365.25+1)/365.25) or better (365.2421874+1)/365.2421874 velocity dailly. See new Meeus page 83}

//begin
//  wtime2actual:=fnmodulo((long)+siderealtime2000 +(julian-2451545 )* earth_angular_velocity,2*pi); {As in the FITS header in ASTAP the site longitude is positive if east and has to be added to the time}
        {change by time & longitude in 0 ..pi*2, simular as siderial time}
        {2451545...for making dayofyear not to big, otherwise small errors occur in sin and cos}

//  precession3(2451545 {J2000},julian,ra3,dec3); {precession, from J2000 to Jnow}

//  t5:=wtime2actual-ra3;
//  sincos(lat,sin_lat,cos_lat);
//  sincos(dec3,sin_dec,cos_dec);
//  try
//  {***** altitude calculation from RA&DEC, meeus new 12.5 *******}
//  result:=arcsin(SIN_LAT*SIN_DEC+COS_LAT*COS_DEC*COS(T5));
//  except
//  {ignore floating point errors outside builder}
//  end;
//end;


{-----------------------------------------------------------------------}
{ POLAR2: conversion of cartesian coordinates (x,y,z)                   }
{        into polar coordinates (r,theta,phi)                           }
{        (theta in [-pi/2 deg,+pi/2]; phi in [0 ,+ 2*pi radians]        }
{-----------------------------------------------------------------------}
procedure polar2(x,y,z:double;out r,theta,phi:double);
var rho: double;
begin
  rho:=x*x+y*y;  r:=sqrt(rho+z*z);
  phi:=arctan2(y,x);
  if phi<0 then phi:=phi+2*pi;
  rho:=sqrt(rho);
  theta:=arctan2(z,rho);
end;


{----------------------------------------------------------------}
{ EQUHOR: conversion of equatorial into horizontal coordinates   }
{   DEC  : declination (-pi/2 .. +pi/2)                          }
{   TAU  : hour angle (0 .. 2*pi)                                }
{   PHI  : geographical latitude (in rad)                        }
{   H    : altitude (in rad)                                     }
{   AZ   : azimuth (0 deg .. 2*pi rad, counted S->W->N->E->S)    }
{----------------------------------------------------------------}
procedure equhor2 (dec,tau,phi: double; out h,az: double);
var cos_phi,sin_phi, cos_dec,sin_dec,cos_tau, sin_tau, x,y,z, dummy: double;
begin
  sincos(phi,sin_phi,cos_phi);
  sincos(dec,sin_dec,cos_dec);
  sincos(tau,sin_tau,cos_tau);
  x:=cos_dec*sin_phi*cos_tau - sin_dec*cos_phi;
  y:=cos_dec*sin_tau;
  z:=cos_dec*cos_phi*cos_tau + sin_dec*sin_phi;
  polar2(x,y,z, dummy,h,az)
end;


procedure ra_az(ra,de,LAT,LONG,t:double;out azimuth2,altitude2: double);{conversion ra & dec to altitude,azimuth}
{input RA [0..2pi], DEC [-pi/2..+pi/2],lat[-0.5*pi..0.5*pi],long[0..2*pi],time[0..2*pi]}
begin
  EQUHOR2(de,ra-long-t,lat, {var:} altitude2,azimuth2);
  azimuth2:=pi-azimuth2;
  if azimuth2<0 then azimuth2:=azimuth2+2*Pi;
end;


procedure az_ra(az,alt,lat,long,t:double;out ra,dcr: double);{conversion az,alt to ra,dec}
{input AZ [0..2pi], ALT [-pi/2..+pi/2],lat[-0.5*pi..0.5*pi],long[0..2pi],time[0..2*pi]}
begin
  EQUHOR2(alt,az,lat,{var:} dcr,ra);
  ra:=pi-ra+long +t;
  while ra<0 do ra:=ra+2*pi;
  while ra>=2*pi do ra:=ra-2*pi;
end;


function atmospheric_refraction(altitude_real {degrees},p {mbar},t {celsius} :double):double;  {atmospheric refraction correction, input and output in degrees}
var  hn  :real;
begin
  hn:=(altitude_real + 10.3/(altitude_real +5.11))*pi/180; {radians}
  result:=((p/1010)*283/(273+t)) * (1.02/60)/(sin(hn)/cos(hn) ); {note: tan(x) = sin(x)/cos(x)}
 {bases on meeus 1991 page 102, formula 15.4}
end;


procedure altitude_and_refraction(lat,long,julian,temperature,pressure,ra3,dec3: double; out az,alt  : double);{altitude calculation and correction ra, dec for refraction}
{input RA [0..2pi], DEC [-pi/2..+pi/2],lat[-pi/2..pi/2], long[-pi..pi] West NEGATIVE, East POSTIVE !!,time[0..2*pi]}
var wtime2actual   : double;
const
  siderealtime2000=(280.46061837)*pi/180;{[radians],sidereal time at 2000 jan 1.5 UT (12 hours) =Jd 2451545 at meridian greenwich, see new meeus 11.4}
  earth_angular_velocity = pi*2*1.00273790935; {about(365.25+1)/365.25) or better (365.2421874+1)/365.2421874 velocity dailly. See new Meeus page 83}

begin
  wtime2actual:=fnmodulo(+long+siderealtime2000 +(julian-2451545 )* earth_angular_velocity,2*pi);{Local sidereal time. As in the FITS header in ASTAP the site longitude is positive if east and has to be added to the time}
  RA_AZ(ra3,dec3,lat,0,wtime2actual,{var} az,alt);{conversion ra & dec to altitude,azimuth}


 {correct for temperature and correct head.ra0, head.dec0 for refraction}
  if temperature>=100 {999} then temperature:=10 {default temperature celsius};
  az:=az*180/pi;{in degrees}
  alt:=alt*180/pi;
  alt:=alt+atmospheric_refraction(alt,pressure {mbar},temperature {celsius});{astrometric to apparant altitude}


//    AZ_RA(azimuth2,result,LAT,0,wtime2actual, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}

//    RA_AZ((23+9/60)*pi/12,(-6-43/60)*pi/180,(38+55/60)*pi/180,-(5+8/60)*pi/12,(8+(34)/60)*pi/12,{var} azimuth2,altitude2);{conversion ra & dec to altitude,azimuth}
//    RA_AZ2((23+9/60)*pi/12,(-6-43/60)*pi/180,(38+55/60)*pi/180,0,(8-5+(34-8)/60)*pi/12,{var} azimuth2,altitude2);{conversion ra & dec to altitude,azimuth}
//    RA_AZ2((23+9/60)*pi/12,(-6-43/60)*pi/180,(38+55/60)*pi/180,+(5+8/60)*pi/12,(8+(34)/60)*pi/12,{var} azimuth2,altitude2);{conversion ra & dec to altitude,azimuth}
//    AZ_RA(AZIMUTH2,ALTITUDE2,39*pi/180,0,(8-5+(34-8)/60)*pi/12, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
//    AZ_RA2(AZIMUTH2,ALTITUDE2,39*pi/180,0,(8-5+(34-8)/60)*pi/12, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
//    AZ_RA2(AZIMUTH2,ALTITUDE2,39*pi/180,+(5+8/60)*pi/12,(8+(34)/60)*pi/12, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
//    beep;
end;

function get_lat_long(out site_lat_radians, site_long_radians : double): boolean;//retrieve latitude and longitude
var
  errordecode  : boolean;
  err          : integer;
begin
  result:=false;
  if sitelat='' then
  begin
    sitelat:=lat_default;
    sitelong:=long_default;
  end;
  val(sitelat,site_lat_radians,err); {try to process  3.7E+01}
  if err=0 then
    begin site_lat_radians:=site_lat_radians*pi/180; errordecode:=false end
  else  {try to process string 37 00 00}
    dec_text_to_radians(sitelat,site_lat_radians,errordecode);
  if errordecode=false then
  begin
    val(sitelong,site_long_radians,err); {try to process  3.7E+01}
    if err=0 then
      begin site_long_radians:=site_long_radians*pi/180; errordecode:=false end
    else  {try to process string  37 00 00}
      dec_text_to_radians(sitelong,site_long_radians,errordecode);

    if errordecode=false then result:=true;
  end;

  if errordecode then memo2_message('Error decoding site longitude or latitude!');
end;

procedure calculate_az_alt(calc_mode : integer;head: Theader; out az,alt : double);{calculate az, alt. Move try to use header values else force calculation. Unit degrees}
var
  site_lat_radians,site_long_radians,ra,dec : double;
  errordecode  : boolean;
  err          : integer;
begin
  {calc_mode 0: use from header or calculate from position. If not available  calculate}
  {calc_mode 1: force calculation from time, location and position without nutation and aberration}
  {calc_mode 2: force high accuracy calculation including nutation and aberration) from time, location and position}
  az:=strtofloat2(centaz);
  alt:=strtofloat2(centalt);

  if (((alt=0) or (calc_mode>0)) and (head.cd1_1<>0)) then {calculate from observation location, image center and time the altitude}
  begin
    if get_lat_long(site_lat_radians, site_long_radians) then
    begin
      date_to_jd(head.date_obs,head.date_avg,head.exposure);{convert date-obs to jd_start, jd_mid}
      if jd_mid>2400000 then {valid JD}
      begin
        ra:=head.ra0; {duplicate to protect J2000 position}
        dec:=head.dec0;
        if calc_mode=2 then {high accuracy including nutation and aberration}
          J2000_to_apparent(jd_mid,ra,dec)  {from J2000 to Jnow apparent, aberrration, precession nutation without refraction}
        else
          precession3(2451545 {J2000},jd_mid,ra,dec); {from J2000 to Jnow mean, precession only. without refraction}

        altitude_and_refraction(site_lat_radians,site_long_radians,jd_mid,focus_temp,pressure,ra,dec,az,alt);{In formulas the longitude is positive to west!!!. }
      end
      else memo2_message('Error decoding Julian day!');
    end;
  end;
end;


function calculate_az_alt_basic(ra,dec : double; out az,alt : double): boolean;{calculate azimuth, altitude and  initialize wtime2actual/sidereal time if site_lat_radians>999. For mouse pointer}
const
  siderealtime2000=(280.46061837)*pi/180;{[radians],sidereal time at 2000 jan 1.5 UT (12 hours) =Jd 2451545 at meridian greenwich, see new meeus 11.4}
  earth_angular_velocity = pi*2*1.00273790935; {about(365.25+1)/365.25) or better (365.2421874+1)/365.2421874 velocity dailly. See new Meeus page 83}
var
  temperature : double;
begin
  result:=false;//assume failure
  if site_lat_radians>998 then  //initialize wtime2actual/sidereal time
  begin
    if get_lat_long(site_lat_radians, site_long_radians)=false then exit;//retrieve latitude and longitude
    date_to_jd(head.date_obs,head.date_avg,head.exposure);{convert date-obs to jd_start, jd_mid}
    if jd_mid>2400000 then {valid JD}
    begin
      wtime2actual:=fnmodulo(+site_long_radians+siderealtime2000 +(jd_mid-2451545 )* earth_angular_velocity,2*pi);{Local sidereal time. As in the FITS header in ASTAP the site longitude is positive if east and has to be added to the time}
    end
    else
    begin
      memo2_message('Error decoding Julian day!');
      exit;
    end;
  end;


  precession3(2451545 {J2000},jd_mid,ra,dec); {from J2000 to Jnow mean, precession only. without refraction}
  ra_az(ra,dec,site_lat_radians,0,wtime2actual,{out} az,alt);{conversion ra & dec to altitude,azimuth}

  if focus_temp>=100 {999} then temperature:=10 {default temperature celsius} else temperature:=focus_temp;
  alt:=alt*180/pi;
  alt:=(alt+atmospheric_refraction(alt,pressure {mbar},temperature {celsius}))*pi/180;{astrometric to apparant altitude}
  result:=true;
end;


function airmass_calc(h: double): double; // where h is apparent altitude in degrees.
begin
  // Pickering, 2002, https://en.wikipedia.org/wiki/Air_mass_(astronomy)
  if h>=0.0000001 then
    result := 1 / sin((pi/180) * (h + (244 / (165 + 47 * power(h,1.1)))))
  else
    result:=999;
end;


function atmospheric_absorption(airmass: double):double;{magnitudes relative to vacuum}
{The Extinction, Scattering, Absorption due to the atmosphere expressed in magnitudes.
 Reference http://www.icq.eps.harvard.edu/ICQExtinct.html
 see also https://www.skyandtelescope.com/astronomy-resources/transparency-and-atmospheric-extinction/}
 var
  a_ozon,a_ray,a_aer : double;
begin
  a_ozon:=airmass*0.016; {Schaefer's (1992) value Aoz =0.016 magnitudes per air mass for the small ozone component contributing to atmospheric extinction.}
  a_ray:=airmass*0.1451; {Rayleigh scattering by air molecules. Expressed in magnitudes}
  a_aer:=airmass*0.120; {Extinction due to aerosol scattering is due to particulates including dust, water droplets and manmade pollutants. Expressed in magnitudes}
  result:=a_ozon+a_ray+a_aer;{Total extinction, scattering, absorption due to the atmosphere expressed in magnitudes. 0.2811*airmass}
end;






end.