Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AbsTime/AtomicTime #33

Open
ThatcherC opened this issue Aug 25, 2020 · 11 comments
Open

AbsTime/AtomicTime #33

ThatcherC opened this issue Aug 25, 2020 · 11 comments

Comments

@ThatcherC
Copy link
Contributor

I've noticed a time jump in the AbsTime.42 log files output after each run. There's always a jump of ~33 seconds between the first line of the log file and the second. Here's an example from a simulation I ran today:

$ cat IO3/AbsTime.42 
651661164.400000
651661197.984000
651661198.984000
651661199.984000
651661200.984000
...

I think this effect comes from a difference in time calculations between Source/42init.c and Source/42exec.c, shown below. I'm confident that these bits of code produce different results (at a minimum, in 42init.c, AtomicTime = DateToAbsTime(Year,Month,Day,Hour,Minute,Second) - 32.184 in the end, while in 42exec.c, AtomicTime = DateToAbsTime(Year,Month,Day,Hour,Minute,Second+LeapSec); ) but I'm not sure which snippet is the correct one.

42/Source/42init.c

Lines 3998 to 4012 in c8dc07a

/* .. Time */
#if defined _USE_SYSTEM_TIME_
if (TimeMode == EXTERNAL_TIME) {
printf("Initializing with external time\n");
RealSystemTime(&Year,&doy,&Month,&Day,&Hour,&Minute,&Second,DTSIM);
}
#endif
AbsTime0 = DateToAbsTime(Year,Month,Day,Hour,Minute,Second);
doy = MD2DOY(Year,Month,Day);
JulDay = AbsTimeToJD(AbsTime0);
AbsTime = AbsTime0;
AtomicTime = AbsTime - 32.184; /* TAI */
CivilTime = AtomicTime - LeapSec; /* UTC "clock" time */
GpsTime = AtomicTime - 19.0;
JDToGpsTime(JulDay,&GpsRollover,&GpsWeek,&GpsSecond);

42/Source/42exec.c

Lines 103 to 117 in 651ee6b

case EXTERNAL_TIME :
while(CurrTick == PrevTick) {
CurrTick = (long) (1.0E-6*usec()/DTSIM);
}
PrevTick = CurrTick;
SimTime += DTSIM;
itime = (long) ((SimTime+0.5*DTSIM)/(DTSIM));
SimTime = ((double) itime)*DTSIM;
RealSystemTime(&Year,&doy,&Month,&Day,&Hour,&Minute,&Second,DTSIM);
AtomicTime = DateToAbsTime(Year,Month,Day,Hour,Minute,Second+LeapSec);
AbsTime = AtomicTime + 32.184;
JulDay = AbsTimeToJD(AbsTime);
JDToGpsTime(JulDay,&GpsRollover,&GpsWeek,&GpsSecond);
AbsTime0 = AbsTime - SimTime;
break;

The fix is probably to replace the code in one of these snippets with the code from the other, but I'm not sure which is right one. I can't say for sure which way to correct way to calculate these various times, so I would welcome expert opinions!

@ericstoneking
Copy link
Owner

Hi Thatcher,

Time is a pain. I summarize the time relations I use in Docs/42 Overview.pdf, slide 21. AbsTime is in TT.

You are correct that the time is not being initialized correctly given EXTERNAL_TIME. Try this and let me know if it fixes it:


      #if defined _USE_SYSTEM_TIME_
         if (TimeMode == EXTERNAL_TIME) {
            printf("Initializing with External Time\n");
            RealSystemTime(&Year,&doy,&Month,&Day,&Hour,&Minute,&Second,DTSIM);
            
            /* Assume External Time is UTC.  Convert to TT for AbsTime */
            AtomicTime = DateToAbsTime(Year,Month,Day,Hour,Minute,Second+LeapSec);
            AbsTime = AtomicTime + 32.184;
            AbsTimeToDate(AbsTime,&Year,&Month,&Day,&Hour,&Minute,&Second,DTSIM);
         }
      #endif

As an aside, LeapSec is set in Inp_Sim.txt, as "Time Offset". I didn't want to get into the middle of managing leap seconds, so it's up to the user.

Regards,
-Eric

@ThatcherC
Copy link
Contributor Author

Hi Eric,

Thanks for the pointer to "42 Overview.pdf" - I hadn't seen the time slide before and that's very helpful.

I put in the code snippet you suggested and it seems to have done the trick. The AbsTime no longer has that 32 second jump at the start -

$ cat IO3/AbsTime.42
651734613.000000
651734614.384000
651734615.384000
651734616.384000
651734617.384000
...

There is a 384 ms excess between the first and second time steps, but that's okay from my perspective. I would be that the differences comes from my computer taking 384 milliseconds to complete the rest of the initialization process before it enters the main simulation loop. I guess a good way to test that theory would be to see if the delay is different on a computer that's slower or faster than mine.

I created a PR for the fix you described above. I'm not sure how/whether to chase down those extra 384 milliseconds but it'll be nice to have the 32 second gap fixed for now.

Good to know about the leap seconds! I'm sure that would be some tricky code to work out.

Best,
Thatcher

@ericstoneking
Copy link
Owner

Hi Thatcher,

The difference between TT and TAI is 32.184 sec. It could be that my earlier suggestion missed the mark just a little bit, and 384 = 184 + an as-yet-unexplained 200 msec. Something to poke at, if you care to. I'll put it on my to-do list, but I can't spare the time to look at it right now.

Regards,
-Eric

@ThatcherC
Copy link
Contributor Author

Ah interesting - I see what you mean. I might focus on other things for the moment but I'll keep an eye out for a tell-tale 200 ms.

Would it be alright to merge and close Pull Request #34 for now? That would add your suggested code, which does make a big difference at startup.

@ThatcherC
Copy link
Contributor Author

Hi Eric,
I made a little progress on this issue, at least on the 184 msec aspect. I took the code from AdvanceTime in Source/42exec.c and used in the external time initialization part of Source/42init.c. With that change, I get AbsTime logs like this:

$ cat IO3/AbsTime.42
652848816.184000
652848816.884000
652848816.884000
652848816.884000
...

instead of what I had in the previous comments. The issue of the first timestep being off by a few hundred milliseconds is still there, but I am happy to see that at least those second two decimal points are now consistent across timesteps.

I also think the missing few hundred milliseconds comes from how the tick is advanced in AdvanceTime in EXTERNAL mode -

      static long PrevTick = 0;
      static long CurrTick = 1;

...

            case EXTERNAL_TIME :
               while(CurrTick == PrevTick) {
                  CurrTick = (long) (1.0E-6*usec()/DTSIM);
               }
               PrevTick = CurrTick;
               SimTime += DTSIM;

I'm not certain how to fix that yet but I'm pretty sure the solution will be found around this region of code.

For now, can we merge PR #34? I would like to have these time changes on the master branch so I can update some of my local simulations.

Thanks!

  • Thatcher

@ericstoneking
Copy link
Owner

Hi All,

Based on recent feedback from multiple sources, I have disambiguated a long-standing issue with time systems.

All of 42's ephemerides, etc., are provided in Terrestrial Dynamical Time (TT or TDT). So I happily adopted that time system for everything; the global variables Year, Month, ... Second were based on TT, with AbsTime bookkeeping the number of seconds elapsed since J2000.

But an increasing number of folks (you all) have been interfacing 42 with external apps, and have been frustrated trying to synchronize 42 to external clocks. Wall clocks use Universal Time Coordinated (UTC), which differs from TT by roughly a minute (these days). (I haven't looked into whether unix system time is referenced to UTC or TT, so that's an outstanding detail.)

So I've implemented a new struct, DateType, so now there is a TT.Year, TT.Month,...TT.Second and UTC.Year, etc. Synch UTC.foo with your wall clocks, and 42 should handle the UTC<->TT conversions in an appropriate manner. I've checked this change into the GSFC repo, and uploaded it to SourceForge and github.

See Docs/42 Overview.pdf, slide 21 and 42exec.c:AdvanceTime for more about the time systems.

It is, of course, quite possible that I've broken something in the process of making this change. I'm not equipped to exercise everything in some of your setups. My hope is that it will be easier to fix this breakage with the time systems split. Please let me know how it works for you.

Regards,
-Eric

@ThatcherC
Copy link
Contributor Author

Hi Eric,

Thank you for these changes! I haven't seen anything break yet but I will keep an eye out. Very glad to have these timing improvements available.

@PeteBlanchard
Copy link

Eric,

On a related note...is it possible to add a reset of AbsTime0 to the command interpreter (or socket reader)? If one wanted to change the time of a running simulation, where would all the touchpoints that need to be managed (or is it simply AbsTime0)? Would I just need to reload/init everything past it in '42init.c'?

Thanks in advance.

@ericstoneking
Copy link
Owner

Hi Pete,

Hmm, I haven't thought about fiddling with time from the command interpreter, but the socket reader is set up for it, so the command interpreter might feature it by accident. The socket reader looks for "TIME %ld-%ld-%ld:%ld:%lf\n", and resets all the time-related variables to match. See Source/IPC/SimRead*.c and search for RequestTimeRefresh. DynTime0 (was AbsTime0) handling varies depending on TimeMode. See Source/42exec.c:AdvanceTime().

@PeteBlanchard
Copy link

PeteBlanchard commented Oct 6, 2020

Ah, could be the slightly older version I am looking at (used by NOS3; still AbsTime0). I had seen that the only time that the TIME (in SimRead*.c) doesn't effect is AbsTime0, I saw that you could (effectively) reset SimTime to start (AbsTime - AbsTime0; where equal) but was wondering more about starting from a new start time without restarting 42... that was why I was asking about re-initializing solar system objects (assuming time is applied to those).

@ericstoneking
Copy link
Owner

Hi Pete,

Yes, the DynTime change is very recent. We can talk in terms of AbsTime, since that's what you're using. Solar system objects are set by AbsTime. When you reset AbsTime, you either have to shift SimTime or AbsTime0 (or both I suppose, if you want). The choice is handled differently (in AdvanceTime) depending on the TimeMode. For EXTERNAL_TIME, I let SimTime be smooth and reset AbsTime0. For NOS3_TIME, I see that AbsTime0 is set at the beginning only, so if AbsTime jumps, SimTime will jump too. I think you have all the pieces you would need to modify this behavior to your situation.

If you're running in EXTERNAL_TIME or NOS3_TIME, then SimTime and AbsTime0 are of secondary importance. All the models run off of AbsTime. AbsTime0 and SimTime are the primary timekeepers for FAST_TIME and REAL_TIME.

Regards,
-Eric

pavelgalchenko added a commit to pavelgalchenko/deepthought that referenced this issue Jul 25, 2023
Bugfixing pavel

Closes ericstoneking#19 and ericstoneking#33

See merge request pavel.galchenko/deepthought!24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants