uncertainties.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* eslint-disable */
  2. import * as MeeusSunMoon from 'meeussunmoon';
  3. import * as luxon from 'luxon';
  4. import { latitudeTihran, longitudeTihran, nawRuzEndTihranUTC, calculateTwinBirthdays } from './generateYearData';
  5. import { BadiDate, badiDateSettings } from '../dist/badiDate-locales';
  6. import { equinoxes } from './equinoxes';
  7. import * as fs from 'fs';
  8. const nearestSunset = (datetime: luxon.DateTime): luxon.DateTime => {
  9. const sunset1 = MeeusSunMoon.sunset(datetime.minus({ days: 1 }), latitudeTihran, longitudeTihran) as luxon.DateTime;
  10. const sunset2 = MeeusSunMoon.sunset(datetime, latitudeTihran, longitudeTihran) as luxon.DateTime;
  11. const sunset3 = MeeusSunMoon.sunset(datetime.plus({ days: 1 }), latitudeTihran, longitudeTihran) as luxon.DateTime;
  12. let sunset = sunset1;
  13. if (Math.abs(datetime.diff(sunset2).valueOf()) < Math.abs(datetime.diff(sunset).valueOf())) {
  14. sunset = sunset2;
  15. }
  16. if (Math.abs(datetime.diff(sunset3).valueOf()) < Math.abs(datetime.diff(sunset).valueOf())) {
  17. sunset = sunset3;
  18. }
  19. return sunset;
  20. };
  21. const nearestNewMoon = (datetime: luxon.DateTime): luxon.DateTime => {
  22. const newMoons = MeeusSunMoon.yearMoonPhases(datetime.year, 0);
  23. let newMoonBefore;
  24. let newMoonAfter;
  25. for (let i = 0; ; i++) {
  26. if (newMoons[i] > datetime) {
  27. newMoonBefore = newMoons[i - 1];
  28. newMoonAfter = newMoons[i];
  29. break;
  30. }
  31. }
  32. if (Math.abs(datetime.diff(newMoonBefore).valueOf()) <
  33. Math.abs(datetime.diff(newMoonAfter).valueOf())) {
  34. return newMoonBefore;
  35. }
  36. return newMoonAfter;
  37. };
  38. /**
  39. * Generate a list to determine uncertainties that could lead to incorrect dates
  40. * in the calculation Columns generated are (all times in UTC, location where
  41. * applicable Tihran):
  42. * Gregorian Year,
  43. * estimated delta T,
  44. * uncertainty in delta T,
  45. * time of the March Equinox,
  46. * time of nearest sunset,
  47. * difference in seconds,
  48. * time of end of Naw-Rúz,
  49. * time of nearest New Moon,
  50. * difference in seconds,
  51. * time of eighth New Moon after Naw-Rúz,
  52. * time of nearest sunset,
  53. * difference in seconds,
  54. * Gregorian Date of March Equinox,
  55. * Badí' date of the Birth of the Báb commemoration,
  56. * corresponding Gregorian date,
  57. * length of Ayyám-i-Há in days
  58. */
  59. const uncertaintyTable = () => {
  60. badiDateSettings({ underlineFormat: 'none' });
  61. let output = 'Gregorian Year, Badíʻ Year, ΔT, σ(ΔT), March equinox, nearest sunset in Tihran, difference [s], ' +
  62. 'end of Naw-Rúz in Tihran, nearest new moon, difference [s], eighth new moon after Naw-Rúz, ' +
  63. 'nearest sunset in Tihran, difference [s], date of Naw-Rúz, date of Birth of the Báb (Badíʻ), ' +
  64. 'date of Birth of the Báb (Gregorian), length of Ayyám-i-Há\n';
  65. for (let i = 0; i < 336; i++) {
  66. const N = i + 10;
  67. const errorDeltaT = Math.round(365.25 * N * Math.sqrt((N * 0.058 / 3) * (1 + N / 2500)) / 1000);
  68. const equinox = luxon.DateTime.fromISO(equinoxes[i], { zone: 'UTC'});
  69. let deltaT;
  70. let t;
  71. if (i < 36) {
  72. t = i + 15;
  73. deltaT = Math.round(62.92 + 0.32217 * t + 0.005589 * t * t);
  74. } else if (i < 136) {
  75. t = i + 2015;
  76. deltaT = Math.round(-20 +
  77. 32 * ((t - 1820) / 100) * ((t - 1820) / 100) - 0.5628 * (2150 - t));
  78. } else {
  79. t = (i + 195) / 100;
  80. deltaT = Math.round(-20 + 32 * t * t);
  81. }
  82. const sunset = nearestSunset(equinox);
  83. let nawRuzEnd = nawRuzEndTihranUTC(equinox.toISO());
  84. const nawRuzNewMoon = nearestNewMoon(nawRuzEnd);
  85. const newMoons = MeeusSunMoon.yearMoonPhases(nawRuzEnd.year, 0);
  86. let index = 0;
  87. // Count the new moons since Naw-Rúz and keep the eighth one
  88. let eighthNewMoon;
  89. for (let j = 0; j < newMoons.length; j++) {
  90. if (newMoons[j] > nawRuzEnd) {
  91. index++;
  92. }
  93. if (index === 8) {
  94. eighthNewMoon = newMoons[j];
  95. break;
  96. }
  97. }
  98. const TBSunset = nearestSunset(eighthNewMoon);
  99. const twinBirth = calculateTwinBirthdays(nawRuzEndTihranUTC(equinox.toISO()));
  100. const BoB = new BadiDate({ year: i + 172, month: twinBirth[0], day: twinBirth[1] });
  101. output += `${equinox.year},`;
  102. output += `${equinox.year - 1843},`;
  103. output += `${deltaT},`;
  104. output += `${errorDeltaT},`;
  105. output += equinox.toFormat(`yyyy-MM-dd'T'HH:mm:ss','`);
  106. output += sunset.toFormat(`yyyy-MM-dd'T'HH:mm:ss','`);
  107. if (Math.abs(equinox.diff(sunset).as('seconds')) < 3 * errorDeltaT + 90) {
  108. output += '#';
  109. }
  110. output += `${equinox.diff(sunset).as('seconds')},`;
  111. output += nawRuzEnd.toFormat(`yyyy-MM-dd'T'HH:mm:ss','`);
  112. output += nawRuzNewMoon.toFormat(`yyyy-MM-dd'T'HH:mm:ss','`);
  113. if (Math.abs(nawRuzEnd.diff(nawRuzNewMoon).as('seconds')) <
  114. 3 * errorDeltaT + 60) {
  115. output += '#';
  116. }
  117. output += `${nawRuzEnd.diff(nawRuzNewMoon).as('seconds')},`;
  118. output += eighthNewMoon.toFormat(`yyyy-MM-dd'T'HH:mm:ss','`);
  119. output += TBSunset.toFormat(`yyyy-MM-dd'T'HH:mm:ss','`);
  120. if (Math.abs(eighthNewMoon.diff(TBSunset).as('seconds')) <
  121. 3 * errorDeltaT + 60) {
  122. output += '#';
  123. }
  124. output += `${eighthNewMoon.diff(TBSunset).as('seconds')},`;
  125. output += nawRuzEnd.toFormat(`dd MMM','`);
  126. output += BoB.format('d MM,');
  127. output += BoB.gregorianDate.toFormat(`dd MMM','`);
  128. output += BoB.ayyamiHaLength;
  129. output += '\n';
  130. }
  131. fs.writeFileSync('./res/uncertainties.csv', output, 'utf8');
  132. };
  133. uncertaintyTable();