From d52b33b7bfdc561c10d89097623172a29bd2240b Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Tue, 16 Dec 2025 16:25:44 -0600 Subject: [PATCH 1/8] Reset the cycle tics when set_cycle or add_cycle is called after a DR group is initialized --- include/trick/DataRecordGroup.hh | 5 +++++ .../sim_services/DataRecord/DataRecordGroup.cpp | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/trick/DataRecordGroup.hh b/include/trick/DataRecordGroup.hh index 79c6c3270..03a039d08 100644 --- a/include/trick/DataRecordGroup.hh +++ b/include/trick/DataRecordGroup.hh @@ -470,6 +470,11 @@ namespace Trick { * @param curr_tic_in - time in tics to match and advance the next cycle tic */ void advance_log_tics_given_curr_tic(long long curr_tic_in); + + /** + * Reset all the logging rates cycles and next tics as if coming out of restart or a run-time set_cycle call + */ + void reset_cycle_data_from_curr_tic(); } ; } ; diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index 3201d6e0e..48d6abaa7 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -177,12 +177,18 @@ const std::string & Trick::DataRecordGroup::get_group_name() { int Trick::DataRecordGroup::set_cycle( double in_cycle ) { logging_rates[0].set_rate(in_cycle); write_job->set_cycle(in_cycle) ; + if(inited) { + reset_cycle_data_from_curr_tic(); + } return(0) ; } int Trick::DataRecordGroup::add_cycle(double in_cycle) { logging_rates.emplace_back(in_cycle); + if(inited) { + reset_cycle_data_from_curr_tic(); + } return(0); } @@ -620,14 +626,19 @@ int Trick::DataRecordGroup::restart() { init() ; // Account for the fact that the current time tics is actually already passed for a checkpoint. + reset_cycle_data_from_curr_tic(); + + return 0 ; +} + +void Trick::DataRecordGroup::reset_cycle_data_from_curr_tic() +{ long long curr_tics = exec_get_time_tics(); advance_log_tics_given_curr_tic(curr_tics); write_job->next_tics = calculate_next_logging_tic(curr_tics); write_job->cycle_tics = write_job->next_tics - curr_tics; write_job->cycle = (double)write_job->cycle_tics / Trick::JobData::time_tic_value; - - return 0 ; } int Trick::DataRecordGroup::write_header() { From d69d6789f539d4df739d9165c018349beb80bddf Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Wed, 17 Dec 2025 14:54:32 -0600 Subject: [PATCH 2/8] Fixed potential logging offset when checkpoint is taken off the dr group's cycle boundary. Updated test to test this case. --- .../RUN_test9/dump.py | 2 +- .../RUN_test9/unit_test.py | 2 +- .../sim_services/DataRecord/DataRecordGroup.cpp | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/test/SIM_checkpoint_data_recording/RUN_test9/dump.py b/test/SIM_checkpoint_data_recording/RUN_test9/dump.py index 89a413d4a..d5689aca1 100644 --- a/test/SIM_checkpoint_data_recording/RUN_test9/dump.py +++ b/test/SIM_checkpoint_data_recording/RUN_test9/dump.py @@ -9,7 +9,7 @@ def main(): drg[DR_GROUP_ID].set_cycle(0.1) drg[DR_GROUP_ID].add_cycle(0.25) - trick.checkpoint(7.0) + trick.checkpoint(7.01) trick.stop(10.0) diff --git a/test/SIM_checkpoint_data_recording/RUN_test9/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test9/unit_test.py index 3ee4a6f33..c2003f98c 100644 --- a/test/SIM_checkpoint_data_recording/RUN_test9/unit_test.py +++ b/test/SIM_checkpoint_data_recording/RUN_test9/unit_test.py @@ -5,7 +5,7 @@ def main(): exec(open("Modified_data/foo.dr").read()) # trick.checkpoint(7.0) - trick.add_read(5.0, 'trick.load_checkpoint("RUN_test9/chkpnt_7.000000")') # contains data recording, starts at t=7 + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test9/chkpnt_7.010000")') # contains data recording, starts at t=7.01 trick.stop(10.0) diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index 3201d6e0e..77006983c 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -63,10 +63,17 @@ Trick::LoggingCycle::LoggingCycle(double rate_in) void Trick::LoggingCycle::set_rate(double rate_in) { + long long curr_tic = exec_get_time_tics(); rate_in_seconds = rate_in; long long cycle_tics = (long long)round(rate_in * Trick::JobData::time_tic_value); rate_in_tics = cycle_tics; - next_cycle_in_tics= exec_get_time_tics(); + if((curr_tic % cycle_tics) != 0) + { + next_cycle_in_tics = (curr_tic/cycle_tics) * cycle_tics + cycle_tics; + } else + { + next_cycle_in_tics = curr_tic; + } } Trick::DataRecordGroup::DataRecordGroup( std::string in_name, Trick::DR_Type dr_type ) : @@ -839,10 +846,11 @@ void Trick::DataRecordGroup::advance_log_tics_given_curr_tic(long long curr_tic_ { for(size_t cycleIndex = 0; cycleIndex < logging_rates.size(); ++cycleIndex) { - long long logNextTic = logging_rates[cycleIndex].next_cycle_in_tics; - if(logNextTic == curr_tic_in) + long long & logNextTic = logging_rates[cycleIndex].next_cycle_in_tics; + + while(logNextTic <= curr_tic_in) { - logging_rates[cycleIndex].next_cycle_in_tics += logging_rates[cycleIndex].rate_in_tics; + logNextTic += logging_rates[cycleIndex].rate_in_tics; } } } From c4345214d1274039d90011c05889b0f8a4383a50 Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Fri, 6 Feb 2026 17:27:44 -0600 Subject: [PATCH 3/8] If a DR group is intiailized and set_cycle is called, recalculate the rates and reset the next_cycle tics to the proper value --- include/trick/DataRecordGroup.hh | 41 ++- include/trick/MultiDtIntegLoopScheduler.hh | 6 +- test/SIM_checkpoint_data_recording/README.md | 6 + .../RUN_test10/dump.py | 45 +++ .../RUN_test10/ref_log_foo2.csv | 266 ++++++++++++++++++ .../RUN_test10/unit_test.py | 13 + test_sims.yml | 6 +- .../DataRecord/DataRecordGroup.cpp | 204 ++++++++++---- 8 files changed, 530 insertions(+), 57 deletions(-) create mode 100644 test/SIM_checkpoint_data_recording/RUN_test10/dump.py create mode 100644 test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv create mode 100644 test/SIM_checkpoint_data_recording/RUN_test10/unit_test.py diff --git a/include/trick/DataRecordGroup.hh b/include/trick/DataRecordGroup.hh index 60df9c324..59ca01e3e 100644 --- a/include/trick/DataRecordGroup.hh +++ b/include/trick/DataRecordGroup.hh @@ -70,6 +70,7 @@ namespace Trick { LoggingCycle(double rate_in); LoggingCycle() = default; void set_rate(double rate_in); + static long long calc_next_tics_on_or_after_input_tic(long long input_tic, long long cycle_tic); double rate_in_seconds{}; /* (s) Logging rate in seconds */ long long rate_in_tics{}; /* (--) Logging rate in sim tics */ long long next_cycle_in_tics{}; /* (--) Next cycle in tics for logging */ @@ -192,6 +193,18 @@ namespace Trick { */ int set_job_class(std::string in_class) ; + /** + * Get the total number of rates for this DataRecordGroup instance + * @return total number of rates + */ + size_t get_num_rates(); + + /** + * Get the logging rate according to rate index + * @return cycle in seconds or -1.0 if error + */ + double get_rate(const size_t rateIdx = 0); + /** @brief @userdesc Command to set the rate at which the group's data is recorded (default is 0.1). @par Python Usage: @@ -206,10 +219,19 @@ namespace Trick { @par Python Usage: @code .add_cycle() @endcode @param in_cycle - the recording rate in seconds - @return always 0 + @return vector index of the added rate */ int add_cycle(double in_cycle) ; + /** + * Updates a logging rate by index and cycle. Calling with 0 + * index is equivalent to set_cycle + * @param rate_idx index of the added rate + * @param rate_in New integration rate in seconds + * @return Zero = success, non-zero = failure (rateIdx is invalid). + */ + int set_rate(const size_t rate_idx, const double rate_in); + /** @brief @userdesc Command to set the phase where the group's data is record (default is 60000). @par Python Usage: @@ -450,14 +472,27 @@ namespace Trick { /** Data thread condition mutex. */ pthread_mutex_t buffer_mutex; /**< trick_io(**) */ - /** Current time saved in Trick::DataRecordGroup::data_record.\n */ + /** Current time saved in Trick::DataRecordGroup::data_record when a buffer is written \n */ double curr_time ; /**< trick_io(*i) trick_units(--) */ + /** Current time saved in Trick::DataRecordGroup::data_record the job was recorded. \n */ + double curr_time_dr_job ; /**< trick_io(*i) trick_units(--) */ + /** * Vector of logging rate objects. */ std::vector logging_rates; + bool check_if_rates_are_valid(); + + /** + * Check if a rate is valid for logging + * next logging time in tics. + * @param rate_in New integration rate in seconds + * @return 0 if valid, 1 if too small, 2 if rate is 0, 3 if it cannot be exactly scheduled + */ + int check_if_rate_is_valid(double test_rate); + /** * Loop through the required logging rates and calculate the * next logging time in tics. @@ -465,6 +500,8 @@ namespace Trick { */ long long calculate_next_logging_tic(long long min_tic); + void emit_rate_error(int rate_err_code, size_t log_idx, double err_rate); + /** * Loop through the required logging rates and advance the next cycle tics of matching rates * @param curr_tic_in - time in tics to match and advance the next cycle tic diff --git a/include/trick/MultiDtIntegLoopScheduler.hh b/include/trick/MultiDtIntegLoopScheduler.hh index ab2506270..ab58d1b2e 100644 --- a/include/trick/MultiDtIntegLoopScheduler.hh +++ b/include/trick/MultiDtIntegLoopScheduler.hh @@ -111,9 +111,9 @@ public: /** * Updates an integration rate by index and cycle. Calling with 0 - * index is equivalent to set_integ_cycle - * @param rateIdx New integration rate in seconds - * @param integRateIn index of the added rate + * index is equivalent to set_integ_cycle * + * @param rateIdx index of the added rate + * @param integRateIn New integration rate in seconds * @return Zero = success, non-zero = failure (rateIdx is invalid). */ virtual int set_integ_rate(const size_t rateIdx, const double integRateIn); diff --git a/test/SIM_checkpoint_data_recording/README.md b/test/SIM_checkpoint_data_recording/README.md index d2def149f..fb13d3315 100644 --- a/test/SIM_checkpoint_data_recording/README.md +++ b/test/SIM_checkpoint_data_recording/README.md @@ -54,4 +54,10 @@ RUN started with different logging setup Checkpoint loaded at t=5 Expected: logging with multiple rates to start from t=7.01+ with no offset +RUN_test10 +Checkpoint dumped with at t=7.01 with multiple loggings rates and multiple calls to set the cycle of both rates throughout the RUN +RUN started with different logging setup +Checkpoint loaded at t=5 +Expected: the varying logging rates specified in add_reads to be processed starting from t=7.01+ with no offset. + Overall: expectation is that what loads in from the checkpoint should take precedence and overwrite the file of the same name. diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py new file mode 100644 index 000000000..b75c3ff17 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py @@ -0,0 +1,45 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo2.dr").read()) + + dr_group = drg[DR_GROUP_ID] + + dr_group.set_cycle(0.1) + dr_group.add_cycle(100.0) + + trick.checkpoint(7.01) + + trick.exec_set_job_cycle("testSimObject.my_foo.increment", 0, 0.1) + + ss_end = 1800.0-1789.0 + cs_end = 30600.0-20000-1789.0 + cs_logging_break = 28796.6-20000-1789.0 + ph_logging_break = 1796.6-1789.0 + + ss_end = 1800.0 + cs_end = 36000.0 + cs_logging_break = 28796.6 + second_cycle_update = ((cs_end-1.1)+(ss_end+2.4))/2 + ph_logging_break = 1796.6 + + print("time 0, cycle = 0.1") + print(f'time {2.4}, cycle = {ph_logging_break}') + print(f'time {ss_end-1.1}, cycle = {0.1}') + print(f'time {ss_end+2.4}, cycle = {cs_logging_break}') + print(f'time {second_cycle_update}, 2nd cycle = {cs_logging_break/4}') + print(f'time {cs_end-1.1}, cycle = {0.1}') + print(f'stop = {cs_end+2.6}') + + trick.add_read(2.4,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle({ph_logging_break})') + trick.add_read(ss_end-1.1,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.1)') + trick.add_read(ss_end+2.4,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle({cs_logging_break})') + trick.add_read(second_cycle_update,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {cs_logging_break/4})') + trick.add_read(cs_end-1.1,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.1)') + trick.stop(cs_end+2.6) + +if __name__ == "__main__": + main() diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv b/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv new file mode 100644 index 000000000..3ed9225c3 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv @@ -0,0 +1,266 @@ +sys.exec.out.time {s},testSimObject.my_foo.b {1} + 100,2002 + 200,4002 + 300,6002 + 400,8002 + 500,10002 + 600,12002 + 700,14002 + 800,16002 + 900,18002 + 1000,20002 + 1100,22002 + 1200,24002 + 1300,26002 + 1400,28002 + 1500,30002 + 1600,32002 + 1700,34002 + 1796.6,35934 + 1798.9,35980 + 1799,35982 + 1799.1,35984 + 1799.2,35986 + 1799.3,35988 + 1799.4,35990 + 1799.5,35992 + 1799.6,35994 + 1799.7,35996 + 1799.8,35998 + 1799.9,36000 + 1800,36002 + 1800.1,36004 + 1800.2,36006 + 1800.3,36008 + 1800.4,36010 + 1800.5,36012 + 1800.6,36014 + 1800.7,36016 + 1800.8,36018 + 1800.9,36020 + 1801,36022 + 1801.1,36024 + 1801.2,36026 + 1801.3,36028 + 1801.4,36030 + 1801.5,36032 + 1801.6,36034 + 1801.7,36036 + 1801.8,36038 + 1801.9,36040 + 1802,36042 + 1802.1,36044 + 1802.2,36046 + 1802.3,36048 + 1900,38002 + 2000,40002 + 2100,42002 + 2200,44002 + 2300,46002 + 2400,48002 + 2500,50002 + 2600,52002 + 2700,54002 + 2800,56002 + 2900,58002 + 3000,60002 + 3100,62002 + 3200,64002 + 3300,66002 + 3400,68002 + 3500,70002 + 3600,72002 + 3700,74002 + 3800,76002 + 3900,78002 + 4000,80002 + 4100,82002 + 4200,84002 + 4300,86002 + 4400,88002 + 4500,90002 + 4600,92002 + 4700,94002 + 4800,96002 + 4900,98002 + 5000,100002 + 5100,102002 + 5200,104002 + 5300,106002 + 5400,108002 + 5500,110002 + 5600,112002 + 5700,114002 + 5800,116002 + 5900,118002 + 6000,120002 + 6100,122002 + 6200,124002 + 6300,126002 + 6400,128002 + 6500,130002 + 6600,132002 + 6700,134002 + 6800,136002 + 6900,138002 + 7000,140002 + 7100,142002 + 7200,144002 + 7300,146002 + 7400,148002 + 7500,150002 + 7600,152002 + 7700,154002 + 7800,156002 + 7900,158002 + 8000,160002 + 8100,162002 + 8200,164002 + 8300,166002 + 8400,168002 + 8500,170002 + 8600,172002 + 8700,174002 + 8800,176002 + 8900,178002 + 9000,180002 + 9100,182002 + 9200,184002 + 9300,186002 + 9400,188002 + 9500,190002 + 9600,192002 + 9700,194002 + 9800,196002 + 9900,198002 + 10000,200002 + 10100,202002 + 10200,204002 + 10300,206002 + 10400,208002 + 10500,210002 + 10600,212002 + 10700,214002 + 10800,216002 + 10900,218002 + 11000,220002 + 11100,222002 + 11200,224002 + 11300,226002 + 11400,228002 + 11500,230002 + 11600,232002 + 11700,234002 + 11800,236002 + 11900,238002 + 12000,240002 + 12100,242002 + 12200,244002 + 12300,246002 + 12400,248002 + 12500,250002 + 12600,252002 + 12700,254002 + 12800,256002 + 12900,258002 + 13000,260002 + 13100,262002 + 13200,264002 + 13300,266002 + 13400,268002 + 13500,270002 + 13600,272002 + 13700,274002 + 13800,276002 + 13900,278002 + 14000,280002 + 14100,282002 + 14200,284002 + 14300,286002 + 14400,288002 + 14500,290002 + 14600,292002 + 14700,294002 + 14800,296002 + 14900,298002 + 15000,300002 + 15100,302002 + 15200,304002 + 15300,306002 + 15400,308002 + 15500,310002 + 15600,312002 + 15700,314002 + 15800,316002 + 15900,318002 + 16000,320002 + 16100,322002 + 16200,324002 + 16300,326002 + 16400,328002 + 16500,330002 + 16600,332002 + 16700,334002 + 16800,336002 + 16900,338002 + 17000,340002 + 17100,342002 + 17200,344002 + 17300,346002 + 17400,348002 + 17500,350002 + 17600,352002 + 17700,354002 + 17800,356002 + 17900,358002 + 18000,360002 + 18100,362002 + 18200,364002 + 18300,366002 + 18400,368002 + 18500,370002 + 18600,372002 + 18700,374002 + 18800,376002 + 18900,378002 + 21597.45,431950 + 28796.6,575934 + 35995.75,719916 + 35998.9,719980 + 35999,719982 + 35999.1,719984 + 35999.2,719986 + 35999.3,719988 + 35999.4,719990 + 35999.5,719992 + 35999.6,719994 + 35999.7,719996 + 35999.8,719998 + 35999.9,720000 + 36000,720002 + 36000.1,720004 + 36000.2,720006 + 36000.3,720008 + 36000.4,720010 + 36000.5,720012 + 36000.6,720014 + 36000.7,720016 + 36000.8,720018 + 36000.9,720020 + 36001,720022 + 36001.1,720024 + 36001.2,720026 + 36001.3,720028 + 36001.4,720030 + 36001.5,720032 + 36001.6,720034 + 36001.7,720036 + 36001.8,720038 + 36001.9,720040 + 36002,720042 + 36002.1,720044 + 36002.2,720046 + 36002.3,720048 + 36002.4,720050 + 36002.5,720052 + 36002.6,720054 diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test10/unit_test.py new file mode 100644 index 000000000..431dba2d2 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test10/unit_test.py @@ -0,0 +1,13 @@ +import trick + +def main(): + + exec(open("Modified_data/foo.dr").read()) + + # trick.checkpoint(7.0) + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test10/chkpnt_7.010000")') # contains data recording, starts at t=7.01 + + trick.stop(10.0) + +if __name__ == "__main__": + main() diff --git a/test_sims.yml b/test_sims.yml index 6d4c924a4..61f1e6f15 100644 --- a/test_sims.yml +++ b/test_sims.yml @@ -275,7 +275,7 @@ SIM_checkpoint_data_recording: returns: 0 RUN_test6/dump.py: returns: 0 - RUN_test[7-9]/dump.py: + RUN_test[7-10]/dump.py: phase: -1 returns: 0 @@ -315,6 +315,10 @@ SIM_checkpoint_data_recording: returns: 0 compare: - test/SIM_checkpoint_data_recording/RUN_test9/ref_log_foo2.csv vs. test/SIM_checkpoint_data_recording/RUN_test9/log_foo2.csv + RUN_test10/unit_test.py: + returns: 0 + compare: + - test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv vs. test/SIM_checkpoint_data_recording/RUN_test10/log_foo2.csv SIM_events: path: test/SIM_events diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index d65f96a84..dc5239b23 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -63,17 +63,21 @@ Trick::LoggingCycle::LoggingCycle(double rate_in) void Trick::LoggingCycle::set_rate(double rate_in) { - long long curr_tic = exec_get_time_tics(); rate_in_seconds = rate_in; - long long cycle_tics = (long long)round(rate_in * Trick::JobData::time_tic_value); - rate_in_tics = cycle_tics; - if((curr_tic % cycle_tics) != 0) + rate_in_tics = (long long)round(rate_in * Trick::JobData::time_tic_value); +} + +long long Trick::LoggingCycle::calc_next_tics_on_or_after_input_tic(long long input_tic, long long cycle_tic) +{ + long long next_tic; + if((input_tic % cycle_tic) != 0) { - next_cycle_in_tics = (curr_tic/cycle_tics) * cycle_tics + cycle_tics; + next_tic = (input_tic/cycle_tic) * cycle_tic + cycle_tic; } else { - next_cycle_in_tics = curr_tic; + next_tic = input_tic; } + return next_tic; } Trick::DataRecordGroup::DataRecordGroup( std::string in_name, Trick::DR_Type dr_type ) : @@ -100,7 +104,8 @@ Trick::DataRecordGroup::DataRecordGroup( std::string in_name, Trick::DR_Type dr_ single_prec_only(false), buffer_type(DR_Buffer), job_class("data_record"), - curr_time(0.0) + curr_time(0.0), + curr_time_dr_job(0.0) { union { @@ -181,16 +186,68 @@ const std::string & Trick::DataRecordGroup::get_group_name() { return group_name ; } +size_t Trick::DataRecordGroup::get_num_rates(){ + return logging_rates.size(); +} + +double Trick::DataRecordGroup::get_rate(const size_t rateIdx) +{ + if(rateIdx < logging_rates.size()) + { + return logging_rates[rateIdx].rate_in_seconds; + } + return -1.0; +} + int Trick::DataRecordGroup::set_cycle( double in_cycle ) { - logging_rates[0].set_rate(in_cycle); - write_job->set_cycle(in_cycle) ; - return(0) ; + return set_rate(0, in_cycle); } int Trick::DataRecordGroup::add_cycle(double in_cycle) { logging_rates.emplace_back(in_cycle); - return(0); + set_rate(logging_rates.size()-1, in_cycle); + return (int)logging_rates.size()-1; +} + +int Trick::DataRecordGroup::set_rate(const size_t rate_idx, const double rate_in) +{ + if(rate_idx >= logging_rates.size()) + { + message_publish(MSG_ERROR, "DataRecordGroup ERROR: set_rate: invalid rate idx %lu\n", rate_idx); + return 1; + } + if(inited) { + int ret = check_if_rate_is_valid(rate_in); + if(ret) + { + emit_rate_error(ret, rate_idx, rate_in); + message_publish(MSG_ERROR, "DataRecordGroup ERROR: Rejecting runtime set_rate(%lu, %.16g)\n", rate_idx, rate_in); + return 1; + } + long long prev_log_tics = (long long)round(curr_time_dr_job * Trick::JobData::time_tic_value); + long long curr_time_tic = exec_get_time_tics(); + LoggingCycle & curLog = logging_rates[rate_idx]; + curLog.set_rate(rate_in); + curLog.next_cycle_in_tics = LoggingCycle::calc_next_tics_on_or_after_input_tic(curr_time_tic, curLog.rate_in_tics); + if(curLog.next_cycle_in_tics == curr_time_tic && curLog.next_cycle_in_tics == prev_log_tics) + { + curLog.next_cycle_in_tics += curLog.rate_in_tics; + } + for(auto & logCycle : logging_rates) + { + logCycle.next_cycle_in_tics = 0; + } + advance_log_tics_given_curr_tic(curr_time_tic-1); + write_job->next_tics = calculate_next_logging_tic(curr_time_tic-1); + + long long next_next_tics = calculate_next_logging_tic(write_job->next_tics); + write_job->cycle_tics = next_next_tics - write_job->next_tics; + write_job->cycle = (double)write_job->cycle_tics / Trick::JobData::time_tic_value; + } else { + logging_rates[rate_idx].set_rate(rate_in); + } + return 0; } int Trick::DataRecordGroup::set_phase( unsigned short in_phase ) { @@ -442,46 +499,12 @@ int Trick::DataRecordGroup::init(bool is_restart) { if(!is_restart) { - long long curr_tics = exec_get_time_tics(); - int tic_value = exec_get_time_tic_value(); - - for(size_t ii = 0; ii < logging_rates.size(); ++ii) + if(!check_if_rates_are_valid()) { - double logging_rate = logging_rates[ii].rate_in_seconds; - if(logging_rate < (1.0 / tic_value)) - { - message_publish( - MSG_ERROR, - "DataRecordGroup ERROR: Cycle for %lu logging rate idx is less than time tic value. cycle = " - "%16.12f, time_tic = %16.12f\n", - ii, - logging_rate, - tic_value); - ret = -1; - } - long long cycle_tics = (long long)round(logging_rate * Trick::JobData::time_tic_value); - - /* Calculate the if the cycle_tics would be a whole number */ - double test_rem = fmod(logging_rate * (double)tic_value, 1.0); - - if(test_rem > 0.001) - { - message_publish(MSG_WARNING, - "DataRecordGroup ERROR: Cycle for %lu logging rate idx cannot be exactly scheduled " - "with time tic value. " - "cycle = %16.12f, cycle_tics = %lld , time_tic = %16.12f\n", - ii, - logging_rate, - cycle_tics, - 1.0 / tic_value); - ret = -1; - } - - // We've checked that the rate is achievable. Call set_rate again to make sure the latest time_tic_value - // was utilized for calculated next tics - logging_rates[ii].set_rate(logging_rate); + disable(); + return (1); } - + long long curr_tics = exec_get_time_tics(); write_job->next_tics = curr_tics; long long next_next_tics = calculate_next_logging_tic(write_job->next_tics); @@ -693,6 +716,8 @@ int Trick::DataRecordGroup::data_record(double in_time) { Trick::DataRecordBuffer * drb ; bool change_detected = false ; + curr_time_dr_job = in_time; + //TODO: does not handle bitfields correctly! if ( record == true ) { if ( freq != DR_Always ) { @@ -811,6 +836,83 @@ int Trick::DataRecordGroup::data_record(double in_time) { return(0) ; } +bool Trick::DataRecordGroup::check_if_rates_are_valid() +{ + // long long curr_tics = exec_get_time_tics(); + long long tic_value = Trick::JobData::time_tic_value; + bool areValid = true; + + for(size_t ii = 0; ii < logging_rates.size(); ++ii) + { + double logging_rate = logging_rates[ii].rate_in_seconds; + int ret = check_if_rate_is_valid(logging_rate); + if(ret != 0){ + emit_rate_error(ret, ii, logging_rate); + areValid = false; + } + } + return areValid; +} + +void Trick::DataRecordGroup::emit_rate_error(int rate_err_code, size_t log_idx, double err_rate) +{ + long long tic_value = Trick::JobData::time_tic_value; + if(rate_err_code == 1) { + message_publish( + MSG_ERROR, + "DataRecordGroup ERROR: Cycle for %lu logging rate idx is less than time tic value. cycle = " + "%16.12f, time_tic = %16.12f\n", + log_idx, + err_rate, + tic_value); + } else if(rate_err_code == 2) + { + message_publish(MSG_ERROR, + "DataRecordGroup ERROR: Cycle for %lu logging rate idx is 0\n", + log_idx); + } else if(rate_err_code == 3) + { + long long cycle_tics = (long long)round(err_rate * tic_value); + message_publish(MSG_ERROR, + "DataRecordGroup ERROR: Cycle for %lu logging rate idx cannot be exactly scheduled " + "with time tic value. " + "cycle = %16.12f, cycle_tics = %lld , time_tic = %16.12f\n", + log_idx, + err_rate, + cycle_tics, + 1.0 / tic_value); + } +} + + int Trick::DataRecordGroup::check_if_rate_is_valid(double test_rate) + { + long long tic_value = Trick::JobData::time_tic_value; + int ret = 0; + + double logging_rate = test_rate; + if(logging_rate < (1.0 / tic_value)) + { + ret = 1; + } else { + long long cycle_tics = (long long)round(logging_rate * tic_value); + if(cycle_tics == 0) + { + ret = 2; + } else { + /* Calculate the if the cycle_tics would be a whole number */ + double test_rem = fmod(logging_rate * (double)tic_value, 1.0); + + if(test_rem > 0.001) + { + ret = 3; + } + } + } + + return ret; + } + + /** * Loop through the required logging rates and calculate the * next logging time in tics. @@ -849,8 +951,8 @@ void Trick::DataRecordGroup::advance_log_tics_given_curr_tic(long long curr_tic_ for(size_t cycleIndex = 0; cycleIndex < logging_rates.size(); ++cycleIndex) { long long & logNextTic = logging_rates[cycleIndex].next_cycle_in_tics; - - while(logNextTic <= curr_tic_in) + logNextTic = LoggingCycle::calc_next_tics_on_or_after_input_tic(curr_tic_in, logging_rates[cycleIndex].rate_in_tics); + if(logNextTic <= curr_tic_in) { logNextTic += logging_rates[cycleIndex].rate_in_tics; } From b5753faba25a28288320972cc4bd6d348b106507 Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Fri, 6 Feb 2026 17:43:18 -0600 Subject: [PATCH 4/8] Added invalid set_cycle calls to RUN_test10 --- include/trick/DataRecordGroup.hh | 13 ++++++++---- test/SIM_checkpoint_data_recording/README.md | 2 ++ .../RUN_test10/dump.py | 10 ++++----- .../DataRecord/DataRecordGroup.cpp | 21 +++++-------------- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/include/trick/DataRecordGroup.hh b/include/trick/DataRecordGroup.hh index 59ca01e3e..e5b51538c 100644 --- a/include/trick/DataRecordGroup.hh +++ b/include/trick/DataRecordGroup.hh @@ -483,13 +483,18 @@ namespace Trick { */ std::vector logging_rates; + /** + * Loop through the required logging rates and check if the rates are valid for the time tic value + * @return true if valid, false if an error is detected + */ bool check_if_rates_are_valid(); /** - * Check if a rate is valid for logging - * next logging time in tics. - * @param rate_in New integration rate in seconds - * @return 0 if valid, 1 if too small, 2 if rate is 0, 3 if it cannot be exactly scheduled + * Check if a rate is valid for logging. An invalid rate is detected by + * - being smaller than the time tic value (or 0) + * - not being a whole number when converted to tics * + * @param test_rate Test rate in seconds + * @return 0 if valid, 1 if too small, 2 if it cannot be exactly scheduled */ int check_if_rate_is_valid(double test_rate); diff --git a/test/SIM_checkpoint_data_recording/README.md b/test/SIM_checkpoint_data_recording/README.md index fb13d3315..daf8297f3 100644 --- a/test/SIM_checkpoint_data_recording/README.md +++ b/test/SIM_checkpoint_data_recording/README.md @@ -55,6 +55,8 @@ Checkpoint loaded at t=5 Expected: logging with multiple rates to start from t=7.01+ with no offset RUN_test10 +Configured the increment job to execute at 0.1 +A runtime invalid set_cycle of 0 is attempted and a set_cycle of 1/128 which the time_tic_value cannot support are both rejected and logging happens as if neither commands are attempted Checkpoint dumped with at t=7.01 with multiple loggings rates and multiple calls to set the cycle of both rates throughout the RUN RUN started with different logging setup Checkpoint loaded at t=5 diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py index b75c3ff17..a9c183996 100644 --- a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py +++ b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py @@ -10,16 +10,11 @@ def main(): dr_group.set_cycle(0.1) dr_group.add_cycle(100.0) - + trick.checkpoint(7.01) trick.exec_set_job_cycle("testSimObject.my_foo.increment", 0, 0.1) - ss_end = 1800.0-1789.0 - cs_end = 30600.0-20000-1789.0 - cs_logging_break = 28796.6-20000-1789.0 - ph_logging_break = 1796.6-1789.0 - ss_end = 1800.0 cs_end = 36000.0 cs_logging_break = 28796.6 @@ -39,6 +34,9 @@ def main(): trick.add_read(ss_end+2.4,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle({cs_logging_break})') trick.add_read(second_cycle_update,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {cs_logging_break/4})') trick.add_read(cs_end-1.1,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.1)') + trick.add_read(1.0, f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.0)') + trick.add_read(2.0, f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {1/128})') + trick.add_read(2.0, f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {1/128})') trick.stop(cs_end+2.6) if __name__ == "__main__": diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index dc5239b23..5b6db825a 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -866,11 +866,6 @@ void Trick::DataRecordGroup::emit_rate_error(int rate_err_code, size_t log_idx, err_rate, tic_value); } else if(rate_err_code == 2) - { - message_publish(MSG_ERROR, - "DataRecordGroup ERROR: Cycle for %lu logging rate idx is 0\n", - log_idx); - } else if(rate_err_code == 3) { long long cycle_tics = (long long)round(err_rate * tic_value); message_publish(MSG_ERROR, @@ -893,19 +888,13 @@ void Trick::DataRecordGroup::emit_rate_error(int rate_err_code, size_t log_idx, if(logging_rate < (1.0 / tic_value)) { ret = 1; - } else { - long long cycle_tics = (long long)round(logging_rate * tic_value); - if(cycle_tics == 0) + } else { + /* Calculate the if the cycle_tics would be a whole number */ + double test_rem = fmod(logging_rate * (double)tic_value, 1.0); + + if(test_rem > 0.001) { ret = 2; - } else { - /* Calculate the if the cycle_tics would be a whole number */ - double test_rem = fmod(logging_rate * (double)tic_value, 1.0); - - if(test_rem > 0.001) - { - ret = 3; - } } } From 54a41bd5a5199887568b3f8d6d083ccb8b30eca7 Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Fri, 6 Feb 2026 18:07:02 -0600 Subject: [PATCH 5/8] Fix syntax for test_sims.yml --- test_sims.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test_sims.yml b/test_sims.yml index 61f1e6f15..f37322ee0 100644 --- a/test_sims.yml +++ b/test_sims.yml @@ -275,7 +275,10 @@ SIM_checkpoint_data_recording: returns: 0 RUN_test6/dump.py: returns: 0 - RUN_test[7-10]/dump.py: + RUN_test[7-9]/dump.py: + phase: -1 + returns: 0 + RUN_test10/dump.py: phase: -1 returns: 0 From e583a12fa76e471abd74125e224f0ce306c1f228 Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Fri, 6 Feb 2026 20:27:15 -0600 Subject: [PATCH 6/8] Add DR Group name to all message_publish calls in DataRecordGroup --- .../sim_services/DataRecord/DataRecordGroup.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index 5b6db825a..858b9b7f6 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -214,7 +214,7 @@ int Trick::DataRecordGroup::set_rate(const size_t rate_idx, const double rate_in { if(rate_idx >= logging_rates.size()) { - message_publish(MSG_ERROR, "DataRecordGroup ERROR: set_rate: invalid rate idx %lu\n", rate_idx); + message_publish(MSG_ERROR, "DataRecordGroup ERROR: DR Group \"%s\" : set_rate: invalid rate idx %lu\n", group_name.c_str(), rate_idx); return 1; } if(inited) { @@ -222,7 +222,7 @@ int Trick::DataRecordGroup::set_rate(const size_t rate_idx, const double rate_in if(ret) { emit_rate_error(ret, rate_idx, rate_in); - message_publish(MSG_ERROR, "DataRecordGroup ERROR: Rejecting runtime set_rate(%lu, %.16g)\n", rate_idx, rate_in); + message_publish(MSG_ERROR, "DataRecordGroup ERROR: DR Group \"%s\" : Rejecting runtime set_rate(%lu, %.16g)\n", group_name.c_str(), rate_idx, rate_in); return 1; } long long prev_log_tics = (long long)round(curr_time_dr_job * Trick::JobData::time_tic_value); @@ -401,7 +401,7 @@ int Trick::DataRecordGroup::add_change_variable( std::string in_name ) { ref2 = ref_attributes(in_name.c_str()) ; if ( ref2 == NULL || ref2->attr == NULL ) { - message_publish(MSG_WARNING, "Could not find Data Record change variable %s.\n", in_name.c_str()) ; + message_publish(MSG_WARNING, "DR Group \"%s\" : Could not find Data Record change variable %s.\n", group_name.c_str(), in_name.c_str()) ; return(-1) ; } @@ -468,14 +468,14 @@ int Trick::DataRecordGroup::init(bool is_restart) { ref2 = ref_attributes(drb->name.c_str()) ; if ( ref2 == NULL || ref2->attr == NULL ) { - message_publish(MSG_WARNING, "Could not find Data Record variable %s.\n", drb->name.c_str()) ; + message_publish(MSG_WARNING, "DR Group \"%s\" : Could not find Data Record variable %s.\n", group_name.c_str(), drb->name.c_str()) ; rec_buffer.erase(rec_buffer.begin() + jj--) ; delete drb ; continue ; } else { std::string message; if (!isSupportedType(ref2, message)) { - message_publish(MSG_WARNING, "%s\n", message.c_str()) ; + message_publish(MSG_WARNING, "DR Group \"%s\" : %s\n", group_name.c_str(), message.c_str()) ; rec_buffer.erase(rec_buffer.begin() + jj--) ; delete drb ; continue ; @@ -860,8 +860,9 @@ void Trick::DataRecordGroup::emit_rate_error(int rate_err_code, size_t log_idx, if(rate_err_code == 1) { message_publish( MSG_ERROR, - "DataRecordGroup ERROR: Cycle for %lu logging rate idx is less than time tic value. cycle = " + "DataRecordGroup ERROR: DR Group \"%s\" : Cycle for %lu logging rate idx is less than time tic value. cycle = " "%16.12f, time_tic = %16.12f\n", + group_name.c_str(), log_idx, err_rate, tic_value); @@ -869,9 +870,10 @@ void Trick::DataRecordGroup::emit_rate_error(int rate_err_code, size_t log_idx, { long long cycle_tics = (long long)round(err_rate * tic_value); message_publish(MSG_ERROR, - "DataRecordGroup ERROR: Cycle for %lu logging rate idx cannot be exactly scheduled " + "DataRecordGroup ERROR: DR Group \"%s\" : Cycle for %lu logging rate idx cannot be exactly scheduled " "with time tic value. " "cycle = %16.12f, cycle_tics = %lld , time_tic = %16.12f\n", + group_name.c_str(), log_idx, err_rate, cycle_tics, From c90850b1a05970df31678a3081426193ebdfc463 Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Mon, 9 Feb 2026 20:21:23 -0600 Subject: [PATCH 7/8] Added DR JobData class so that set_cycle calls DataRecordGroup::set_cycle --- include/trick/DataRecordGroup.hh | 17 +++++++++++++- .../RUN_test10/dump.py | 2 +- .../DataRecord/DataRecordGroup.cpp | 22 ++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/trick/DataRecordGroup.hh b/include/trick/DataRecordGroup.hh index e5b51538c..2054a5741 100644 --- a/include/trick/DataRecordGroup.hh +++ b/include/trick/DataRecordGroup.hh @@ -19,6 +19,8 @@ PROGRAMMERS: namespace Trick { + class DataRecordGroup; + /** * The DR_Freq enumeration represents the possible Trick data recording frequency. */ @@ -76,7 +78,20 @@ namespace Trick { long long next_cycle_in_tics{}; /* (--) Next cycle in tics for logging */ }; - class DataRecordGroup : public Trick::SimObject { + class DataRecordGroupJobData : public JobData + { + public: + DataRecordGroupJobData(DataRecordGroup & owner_in); + DataRecordGroupJobData(DataRecordGroup & owner_in, int in_thread, int in_id, std::string in_job_class_name , void* in_sup_class_data, + double in_cycle, std::string in_name, std::string in_tag = "", int in_phase = 60000 , + double in_start = 0.0 , double in_stop = 1.0e37); + + int set_cycle(double rate) override; + + DataRecordGroup & owner; + }; + + class DataRecordGroup : public SimObject { public: diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py index a9c183996..af2373956 100644 --- a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py +++ b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py @@ -29,7 +29,7 @@ def main(): print(f'time {cs_end-1.1}, cycle = {0.1}') print(f'stop = {cs_end+2.6}') - trick.add_read(2.4,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle({ph_logging_break})') + trick.add_read(2.4,f'trick.exec_set_job_cycle("trick_data_record_group_{dr_group.get_group_name()}.data_record", 1, {ph_logging_break})') trick.add_read(ss_end-1.1,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.1)') trick.add_read(ss_end+2.4,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle({cs_logging_break})') trick.add_read(second_cycle_update,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {cs_logging_break/4})') diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index 858b9b7f6..c2cf7b108 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -80,6 +80,25 @@ long long Trick::LoggingCycle::calc_next_tics_on_or_after_input_tic(long long in return next_tic; } +Trick::DataRecordGroupJobData::DataRecordGroupJobData(Trick::DataRecordGroup &owner_in) + : owner(owner_in) +{ +} + +Trick::DataRecordGroupJobData::DataRecordGroupJobData(Trick::DataRecordGroup &owner_in, int in_thread, int in_id, std::string in_job_class_name, void *in_sup_class_data, + double in_cycle, std::string in_name, std::string in_tag, int in_phase, + double in_start, double in_stop) + : Trick::JobData(in_thread, in_id, in_job_class_name, in_sup_class_data, in_cycle, in_name, in_tag, in_phase, in_start, in_stop), + owner(owner_in) +{ +} + +int Trick::DataRecordGroupJobData::set_cycle(double rate) +{ + owner.set_cycle(rate); + return 0; +} + Trick::DataRecordGroup::DataRecordGroup( std::string in_name, Trick::DR_Type dr_type ) : record(true) , inited(false) , @@ -537,7 +556,8 @@ void Trick::DataRecordGroup::configure_jobs(DR_Type type) { add_job(0, 4, (char *)"post_checkpoint", NULL, 1.0, (char *)"clear_checkpoint_vars", (char *)"TRK") ; add_job(0, 6, (char *)"shutdown", NULL, 1.0, (char *)"shutdown", (char *)"TRK") ; - write_job = add_job(0, 99, (char *)job_class.c_str(), NULL, cycle, (char *)"data_record" , (char *)"TRK") ; + write_job = new Trick::DataRecordGroupJobData(*this, 0, 99, (char *)job_class.c_str(), NULL, cycle, (char *)"data_record" , (char *)"TRK") ; + jobs.push_back(write_job) ; break ; } write_job->set_system_job_class(true); From 12e8524d40eb902b205701d119de789a5349cf45 Mon Sep 17 00:00:00 2001 From: Thomas Brain Date: Mon, 16 Feb 2026 10:48:25 -0600 Subject: [PATCH 8/8] Set enable/disable methods in JobData to virtual and override them in DataRecordGroup so that exec_set_job_onoff works correctly --- include/trick/DataRecordGroup.hh | 6 +- include/trick/JobData.hh | 4 +- .../RUN_test10/dump.py | 13 +- .../RUN_test10/ref_log_foo2.csv | 317 +++++++----------- .../src/SegmentedExecutive.cpp | 7 +- .../DataRecord/DataRecordGroup.cpp | 22 +- .../Executive/Executive_add_jobs_to_queue.cpp | 4 +- .../Executive_check_all_job_cycle_times.cpp | 2 +- .../Executive/Executive_set_job_onoff.cpp | 14 +- .../Executive_set_simobject_onoff.cpp | 11 +- .../InputProcessor/IPPythonEvent.cpp | 21 +- 11 files changed, 186 insertions(+), 235 deletions(-) diff --git a/include/trick/DataRecordGroup.hh b/include/trick/DataRecordGroup.hh index 2054a5741..3f879f5a9 100644 --- a/include/trick/DataRecordGroup.hh +++ b/include/trick/DataRecordGroup.hh @@ -87,6 +87,7 @@ namespace Trick { double in_start = 0.0 , double in_stop = 1.0e37); int set_cycle(double rate) override; + void enable() override; DataRecordGroup & owner; }; @@ -116,9 +117,6 @@ namespace Trick { /** Start time for data recording.\n */ double start; /**< trick_io(*io) trick_units(s) */ - /** Cycle time for data recording.\n */ - double cycle; /**< trick_io(*io) trick_units(s) */ - /* Fake attributes to use for data recording.\n */ ATTRIBUTES time_value_attr; /**< trick_io(**) */ @@ -527,6 +525,8 @@ namespace Trick { * @param curr_tic_in - time in tics to match and advance the next cycle tic */ void advance_log_tics_given_curr_tic(long long curr_tic_in); + + static const double default_cyle; } ; } ; diff --git a/include/trick/JobData.hh b/include/trick/JobData.hh index 3c5fde622..9aace6259 100644 --- a/include/trick/JobData.hh +++ b/include/trick/JobData.hh @@ -172,12 +172,12 @@ namespace Trick { /** * Enable the job. */ - void enable() ; + virtual void enable() ; /** * Disable the job. */ - void disable() ; + virtual void disable() ; /** * Sets the job is handled flag diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py index af2373956..1452d7069 100644 --- a/test/SIM_checkpoint_data_recording/RUN_test10/dump.py +++ b/test/SIM_checkpoint_data_recording/RUN_test10/dump.py @@ -16,10 +16,11 @@ def main(): trick.exec_set_job_cycle("testSimObject.my_foo.increment", 0, 0.1) ss_end = 1800.0 - cs_end = 36000.0 - cs_logging_break = 28796.6 + cs_end = 3600.0 + cs_logging_break = 2879.66 second_cycle_update = ((cs_end-1.1)+(ss_end+2.4))/2 ph_logging_break = 1796.6 + stop_time = cs_end+2.6+10.0 print("time 0, cycle = 0.1") print(f'time {2.4}, cycle = {ph_logging_break}') @@ -27,7 +28,9 @@ def main(): print(f'time {ss_end+2.4}, cycle = {cs_logging_break}') print(f'time {second_cycle_update}, 2nd cycle = {cs_logging_break/4}') print(f'time {cs_end-1.1}, cycle = {0.1}') - print(f'stop = {cs_end+2.6}') + print(f'time {stop_time-6.9}, disable job') + print(f'time {stop_time-4.5}, enable job') + print(f'stop = {stop_time}') trick.add_read(2.4,f'trick.exec_set_job_cycle("trick_data_record_group_{dr_group.get_group_name()}.data_record", 1, {ph_logging_break})') trick.add_read(ss_end-1.1,f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.1)') @@ -37,7 +40,9 @@ def main(): trick.add_read(1.0, f'trick.get_data_record_group("{dr_group.get_group_name()}").set_cycle(0.0)') trick.add_read(2.0, f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {1/128})') trick.add_read(2.0, f'trick.get_data_record_group("{dr_group.get_group_name()}").set_rate(1, {1/128})') - trick.stop(cs_end+2.6) + trick.add_read(stop_time-6.9, f'trick.exec_set_job_onoff("trick_data_record_group_{dr_group.get_group_name()}.data_record", 1, 0)') + trick.add_read(stop_time-4.5, f'trick.exec_set_job_onoff("trick_data_record_group_{dr_group.get_group_name()}.data_record", 1, 1)') + trick.stop(stop_time) if __name__ == "__main__": main() diff --git a/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv b/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv index 3ed9225c3..f49d36eec 100644 --- a/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv +++ b/test/SIM_checkpoint_data_recording/RUN_test10/ref_log_foo2.csv @@ -61,206 +61,119 @@ sys.exec.out.time {s},testSimObject.my_foo.b {1} 2500,50002 2600,52002 2700,54002 - 2800,56002 - 2900,58002 - 3000,60002 - 3100,62002 - 3200,64002 - 3300,66002 - 3400,68002 - 3500,70002 + 2879.66,57594 + 3598.9,71980 + 3599,71982 + 3599.1,71984 + 3599.2,71986 + 3599.3,71988 + 3599.4,71990 + 3599.5,71992 + 3599.575,71992 + 3599.6,71994 + 3599.7,71996 + 3599.8,71998 + 3599.9,72000 3600,72002 - 3700,74002 - 3800,76002 - 3900,78002 - 4000,80002 - 4100,82002 - 4200,84002 - 4300,86002 - 4400,88002 - 4500,90002 - 4600,92002 - 4700,94002 - 4800,96002 - 4900,98002 - 5000,100002 - 5100,102002 - 5200,104002 - 5300,106002 - 5400,108002 - 5500,110002 - 5600,112002 - 5700,114002 - 5800,116002 - 5900,118002 - 6000,120002 - 6100,122002 - 6200,124002 - 6300,126002 - 6400,128002 - 6500,130002 - 6600,132002 - 6700,134002 - 6800,136002 - 6900,138002 - 7000,140002 - 7100,142002 - 7200,144002 - 7300,146002 - 7400,148002 - 7500,150002 - 7600,152002 - 7700,154002 - 7800,156002 - 7900,158002 - 8000,160002 - 8100,162002 - 8200,164002 - 8300,166002 - 8400,168002 - 8500,170002 - 8600,172002 - 8700,174002 - 8800,176002 - 8900,178002 - 9000,180002 - 9100,182002 - 9200,184002 - 9300,186002 - 9400,188002 - 9500,190002 - 9600,192002 - 9700,194002 - 9800,196002 - 9900,198002 - 10000,200002 - 10100,202002 - 10200,204002 - 10300,206002 - 10400,208002 - 10500,210002 - 10600,212002 - 10700,214002 - 10800,216002 - 10900,218002 - 11000,220002 - 11100,222002 - 11200,224002 - 11300,226002 - 11400,228002 - 11500,230002 - 11600,232002 - 11700,234002 - 11800,236002 - 11900,238002 - 12000,240002 - 12100,242002 - 12200,244002 - 12300,246002 - 12400,248002 - 12500,250002 - 12600,252002 - 12700,254002 - 12800,256002 - 12900,258002 - 13000,260002 - 13100,262002 - 13200,264002 - 13300,266002 - 13400,268002 - 13500,270002 - 13600,272002 - 13700,274002 - 13800,276002 - 13900,278002 - 14000,280002 - 14100,282002 - 14200,284002 - 14300,286002 - 14400,288002 - 14500,290002 - 14600,292002 - 14700,294002 - 14800,296002 - 14900,298002 - 15000,300002 - 15100,302002 - 15200,304002 - 15300,306002 - 15400,308002 - 15500,310002 - 15600,312002 - 15700,314002 - 15800,316002 - 15900,318002 - 16000,320002 - 16100,322002 - 16200,324002 - 16300,326002 - 16400,328002 - 16500,330002 - 16600,332002 - 16700,334002 - 16800,336002 - 16900,338002 - 17000,340002 - 17100,342002 - 17200,344002 - 17300,346002 - 17400,348002 - 17500,350002 - 17600,352002 - 17700,354002 - 17800,356002 - 17900,358002 - 18000,360002 - 18100,362002 - 18200,364002 - 18300,366002 - 18400,368002 - 18500,370002 - 18600,372002 - 18700,374002 - 18800,376002 - 18900,378002 - 21597.45,431950 - 28796.6,575934 - 35995.75,719916 - 35998.9,719980 - 35999,719982 - 35999.1,719984 - 35999.2,719986 - 35999.3,719988 - 35999.4,719990 - 35999.5,719992 - 35999.6,719994 - 35999.7,719996 - 35999.8,719998 - 35999.9,720000 - 36000,720002 - 36000.1,720004 - 36000.2,720006 - 36000.3,720008 - 36000.4,720010 - 36000.5,720012 - 36000.6,720014 - 36000.7,720016 - 36000.8,720018 - 36000.9,720020 - 36001,720022 - 36001.1,720024 - 36001.2,720026 - 36001.3,720028 - 36001.4,720030 - 36001.5,720032 - 36001.6,720034 - 36001.7,720036 - 36001.8,720038 - 36001.9,720040 - 36002,720042 - 36002.1,720044 - 36002.2,720046 - 36002.3,720048 - 36002.4,720050 - 36002.5,720052 - 36002.6,720054 + 3600.1,72004 + 3600.2,72006 + 3600.3,72008 + 3600.4,72010 + 3600.5,72012 + 3600.6,72014 + 3600.7,72016 + 3600.8,72018 + 3600.9,72020 + 3601,72022 + 3601.1,72024 + 3601.2,72026 + 3601.3,72028 + 3601.4,72030 + 3601.5,72032 + 3601.6,72034 + 3601.7,72036 + 3601.8,72038 + 3601.9,72040 + 3602,72042 + 3602.1,72044 + 3602.2,72046 + 3602.3,72048 + 3602.4,72050 + 3602.5,72052 + 3602.6,72054 + 3602.7,72056 + 3602.8,72058 + 3602.9,72060 + 3603,72062 + 3603.1,72064 + 3603.2,72066 + 3603.3,72068 + 3603.4,72070 + 3603.5,72072 + 3603.6,72074 + 3603.7,72076 + 3603.8,72078 + 3603.9,72080 + 3604,72082 + 3604.1,72084 + 3604.2,72086 + 3604.3,72088 + 3604.4,72090 + 3604.5,72092 + 3604.6,72094 + 3604.7,72096 + 3604.8,72098 + 3604.9,72100 + 3605,72102 + 3605.1,72104 + 3605.2,72106 + 3605.3,72108 + 3605.4,72110 + 3605.5,72112 + 3605.6,72114 + 3608.1,72164 + 3608.2,72166 + 3608.3,72168 + 3608.4,72170 + 3608.5,72172 + 3608.6,72174 + 3608.7,72176 + 3608.8,72178 + 3608.9,72180 + 3609,72182 + 3609.1,72184 + 3609.2,72186 + 3609.3,72188 + 3609.4,72190 + 3609.5,72192 + 3609.6,72194 + 3609.7,72196 + 3609.8,72198 + 3609.9,72200 + 3610,72202 + 3610.1,72204 + 3610.2,72206 + 3610.3,72208 + 3610.4,72210 + 3610.5,72212 + 3610.6,72214 + 3610.7,72216 + 3610.8,72218 + 3610.9,72220 + 3611,72222 + 3611.1,72224 + 3611.2,72226 + 3611.3,72228 + 3611.4,72230 + 3611.5,72232 + 3611.6,72234 + 3611.7,72236 + 3611.8,72238 + 3611.9,72240 + 3612,72242 + 3612.1,72244 + 3612.2,72246 + 3612.3,72248 + 3612.4,72250 + 3612.5,72252 + 3612.6,72254 diff --git a/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp b/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp index 5f2177050..492f7ab31 100644 --- a/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp +++ b/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp @@ -133,7 +133,12 @@ int Trick::SegmentedExecutive::segment_set_jobs_onoff() { job = *it ; // Test to see if the next segment is present in the job tags. // Set the disabled flag to the negation of the tag's presence - job->disabled = !(job->tags.count(next_segment_str)) ; + if(!(job->tags.count(next_segment_str))) { + job->disable() ; + } else + { + job->enable(); + } message_publish(MSG_NORMAL, "segment set job %s to %s\n" , job->name.c_str() , job->disabled ? "disabled" : "enabled" ) ; } diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index c2cf7b108..7fbba05b7 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -20,6 +20,9 @@ #include "trick/message_proto.h" #include "trick/message_type.h" + +const double Trick::DataRecordGroup::default_cyle = 0.1; + /** @details -# The recording group is enabled @@ -55,7 +58,6 @@ Trick::DataRecordBuffer::~DataRecordBuffer() { free(ref) ; } - Trick::LoggingCycle::LoggingCycle(double rate_in) { set_rate(rate_in); @@ -99,13 +101,21 @@ int Trick::DataRecordGroupJobData::set_cycle(double rate) return 0; } +void Trick::DataRecordGroupJobData::enable() +{ + if(disabled) + { + Trick::JobData::enable(); + owner.set_cycle(owner.get_rate()); + } +} + Trick::DataRecordGroup::DataRecordGroup( std::string in_name, Trick::DR_Type dr_type ) : record(true) , inited(false) , group_name(in_name) , freq(DR_Always), - start(0.0) , - cycle(0.1) , + start(0.0), time_value_attr() , num_variable_names(0), variable_names(NULL), @@ -146,7 +156,7 @@ Trick::DataRecordGroup::DataRecordGroup( std::string in_name, Trick::DR_Type dr_ add_time_variable() ; - logging_rates.emplace_back(cycle); + logging_rates.emplace_back(default_cyle); } Trick::DataRecordGroup::~DataRecordGroup() { @@ -550,13 +560,13 @@ void Trick::DataRecordGroup::configure_jobs(DR_Type type) { // add_jobs_to_queue will fill in job_id later // make the init job run after all other initialization jobs but before the post init checkpoint // job so users can allocate memory in initialization jobs and checkpointing data rec groups will work - add_job(0, 1, (char *)"initialization", NULL, cycle, (char *)"init", (char *)"TRK", 65534) ; + add_job(0, 1, (char *)"initialization", NULL, default_cyle, (char *)"init", (char *)"TRK", 65534) ; add_job(0, 2, (char *)"end_of_frame", NULL, 1.0, (char *)"write_data", (char *)"TRK") ; add_job(0, 3, (char *)"checkpoint", NULL, 1.0, (char *)"checkpoint", (char *)"TRK") ; add_job(0, 4, (char *)"post_checkpoint", NULL, 1.0, (char *)"clear_checkpoint_vars", (char *)"TRK") ; add_job(0, 6, (char *)"shutdown", NULL, 1.0, (char *)"shutdown", (char *)"TRK") ; - write_job = new Trick::DataRecordGroupJobData(*this, 0, 99, (char *)job_class.c_str(), NULL, cycle, (char *)"data_record" , (char *)"TRK") ; + write_job = new Trick::DataRecordGroupJobData(*this, 0, 99, (char *)job_class.c_str(), NULL, default_cyle, (char *)"data_record" , (char *)"TRK") ; jobs.push_back(write_job) ; break ; } diff --git a/trick_source/sim_services/Executive/Executive_add_jobs_to_queue.cpp b/trick_source/sim_services/Executive/Executive_add_jobs_to_queue.cpp index eadbb8d9a..d66b8f25a 100644 --- a/trick_source/sim_services/Executive/Executive_add_jobs_to_queue.cpp +++ b/trick_source/sim_services/Executive/Executive_add_jobs_to_queue.cpp @@ -96,7 +96,7 @@ int Trick::Executive::add_jobs_to_queue( Trick::SimObject * in_sim_object , bool temp_job->calc_cycle_tics() ; if ( temp_job->start > max_time ) { - temp_job->disabled = true ; + temp_job->disable() ; temp_job->start_tics = TRICK_MAX_LONG_LONG ; } else { temp_job->start_tics = (long long)(temp_job->start * time_tic_value) ; @@ -105,7 +105,7 @@ int Trick::Executive::add_jobs_to_queue( Trick::SimObject * in_sim_object , bool if ( temp_job->stop > max_time ) { temp_job->stop_tics = TRICK_MAX_LONG_LONG ; } else if ( temp_job->stop < temp_job->start ) { - temp_job->disabled = true ; + temp_job->disable() ; } else { temp_job->stop_tics = (long long)(temp_job->stop * time_tic_value) ; } diff --git a/trick_source/sim_services/Executive/Executive_check_all_job_cycle_times.cpp b/trick_source/sim_services/Executive/Executive_check_all_job_cycle_times.cpp index 9a67410af..4bccfaeb9 100644 --- a/trick_source/sim_services/Executive/Executive_check_all_job_cycle_times.cpp +++ b/trick_source/sim_services/Executive/Executive_check_all_job_cycle_times.cpp @@ -24,7 +24,7 @@ int Trick::Executive::check_all_job_cycle_times() { if ( temp_job->cycle < (1.0 / time_tic_value) ) { message_publish(MSG_WARNING,"Cycle for (%s) is less than time tic value. cycle = %16.12f, time_tic = %16.12f\n", temp_job->name.c_str() , temp_job->cycle, 1.0 / time_tic_value ) ; - temp_job->disabled = true ; + temp_job->disable() ; temp_job->cycle_tics = TRICK_MAX_LONG_LONG ; temp_job->next_tics = TRICK_MAX_LONG_LONG ; ret = -1 ; diff --git a/trick_source/sim_services/Executive/Executive_set_job_onoff.cpp b/trick_source/sim_services/Executive/Executive_set_job_onoff.cpp index 07aa5e7db..608183047 100644 --- a/trick_source/sim_services/Executive/Executive_set_job_onoff.cpp +++ b/trick_source/sim_services/Executive/Executive_set_job_onoff.cpp @@ -15,14 +15,22 @@ int Trick::Executive::set_job_onoff(std::string job_name, int instance_num , int if ( job != NULL ) { // set disabled flag accordingly for one job (the given job_name) - job->disabled = !on ; + if(on) { + job->enable(); + } else { + job->disable(); + } } else { // job_name may be a tag name: find all jobs that have the given tag name and hold them in a list range = all_tagged_jobs.equal_range(job_name) ; if (range.first != range.second) { // set disabled flag accordingly for all jobs with this tag - for ( it = range.first; it != range.second ; ++it ) { - it->second->disabled = !on ; + for ( it = range.first; it != range.second ; ++it ) { + if(on) { + it->second->enable(); + } else { + it->second->disable(); + } } } else { message_publish(MSG_WARNING, "Warning: Job %s not found in Executive::set_job_onoff\n" , job_name.c_str()) ; diff --git a/trick_source/sim_services/Executive/Executive_set_simobject_onoff.cpp b/trick_source/sim_services/Executive/Executive_set_simobject_onoff.cpp index 60dd5c155..15d2d3c00 100644 --- a/trick_source/sim_services/Executive/Executive_set_simobject_onoff.cpp +++ b/trick_source/sim_services/Executive/Executive_set_simobject_onoff.cpp @@ -33,10 +33,15 @@ int Trick::Executive::set_sim_object_onoff(std::string sim_object_name, int on) for ( int i = 0 ; i < sim_object->jobs.size() ; i++ ) { std::map::iterator saved_state_it = sim_object->saved_job_states.find(sim_object->jobs[i]); if (saved_state_it != sim_object->saved_job_states.end()) { - sim_object->jobs[i]->disabled = saved_state_it->second; + if(saved_state_it->second) + { + sim_object->jobs[i]->disable(); + } else { + sim_object->jobs[i]->enable(); + } } else { // If job is not in map, turn it on - sim_object->jobs[i]->disabled = false; + sim_object->jobs[i]->enable(); } } sim_object->saved_job_states.clear(); @@ -44,7 +49,7 @@ int Trick::Executive::set_sim_object_onoff(std::string sim_object_name, int on) for ( int i = 0 ; i < sim_object->jobs.size() ; i++ ) { // Save state, turn off sim_object->saved_job_states[sim_object->jobs[i]] = sim_object->jobs[i]->disabled; - sim_object->jobs[i]->disabled = true ; + sim_object->jobs[i]->disable() ; } } return(0) ; diff --git a/trick_source/sim_services/InputProcessor/IPPythonEvent.cpp b/trick_source/sim_services/InputProcessor/IPPythonEvent.cpp index c822ddf98..0728a9276 100644 --- a/trick_source/sim_services/InputProcessor/IPPythonEvent.cpp +++ b/trick_source/sim_services/InputProcessor/IPPythonEvent.cpp @@ -220,7 +220,7 @@ int Trick::IPPythonEvent::condition_job(int num, std::string jobname, std::strin } else { if (! job->job_class_name.compare("malfunction")) { // enable it if it's a malf job because they are not in any queue - job->disabled = false; + job->enable(); } condition(num, jobname, comment, NULL, job ); } @@ -374,7 +374,7 @@ int Trick::IPPythonEvent::action_job(int num, std::string jobname, std::string c } else { if (! job->job_class_name.compare("malfunction")) { // enable it if it's a malf job because they are not in any queue - job->disabled = false; + job->enable(); } action(num, jobname, comment, job, 3 ); } @@ -574,9 +574,12 @@ bool Trick::IPPythonEvent::process_user_event( long long curr_time ) { } else if (condition_list[ii]->job != NULL) { // if it's a job, get its return value bool save_disabled_state = condition_list[ii]->job->disabled; - condition_list[ii]->job->disabled = false; + condition_list[ii]->job->enable(); return_val = condition_list[ii]->job->call(); - condition_list[ii]->job->disabled = save_disabled_state; + if(save_disabled_state) + { + condition_list[ii]->job->disable(); + } } else { // otherwise use python to evaluate string std::string full_in_string ; @@ -637,16 +640,18 @@ bool Trick::IPPythonEvent::process_user_event( long long curr_time ) { case 0 : // python, should not get here break; case 1 : // On - action_list[ii]->job->disabled = false; + action_list[ii]->job->enable(); break; case 2 : // Off - action_list[ii]->job->disabled = true; + action_list[ii]->job->disable(); break; case 3 : // Call bool save_disabled_state = action_list[ii]->job->disabled; - action_list[ii]->job->disabled = false; + action_list[ii]->job->enable(); action_list[ii]->job->call(); - action_list[ii]->job->disabled = save_disabled_state; + if(save_disabled_state) { + action_list[ii]->job->disable(); + } break; } } else {