Skip to content

Commit a73466b

Browse files
committed
tweak method timing restrictions
1 parent ea5067c commit a73466b

7 files changed

Lines changed: 39 additions & 17 deletions

File tree

VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ multitrait branch:
194194
did a full re-architecture of how mutations get "retained by the tree sequence" to fix remaining issues:
195195
fix #646: saved mutations can be added later and bypass retained_by_treeseq_
196196
fix #648: saving without simplification results in mutations without metadata
197+
tweak timing restrictions to allow some methods -- notably demandPhenotype() -- to be called from the Eidos console in SLiMgui
197198

198199

199200
version 5.2 (Eidos version 4.2):

core/community_eidos.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,14 @@ EidosSymbolTable *Community::SymbolsFromBaseSymbols(EidosSymbolTable *p_base_sym
193193

194194
void Community::EnforceTimingRestriction_EventBlockOnly(const char *p_method_name, const char *p_eidos_name, const char *p_addendum)
195195
{
196+
SLiMCycleStage cycle_stage = CycleStage();
197+
196198
// TIMING RESTRICTION
197199
// must be called directly from an event block -- not from a callback, even if the callback was triggered inside the event block
200+
// BCH 7/21/2026: It is now also legal to call a method with this restriction from the Eidos console in SLiMgui; that is very similar to an event.
201+
if ((cycle_stage == SLiMCycleStage::kStagePostCycle) && (executing_block_type_ == SLiMEidosBlockType::SLiMEidosNoBlockType))
202+
return;
203+
198204
if ((executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))
199205
EIDOS_TERMINATION << "ERROR (" << p_method_name << "): " << p_eidos_name << " must be called directly from a first(), early(), or late() event" << p_addendum << "." << EidosTerminate();
200206
}

core/individual.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7408,10 +7408,11 @@ void Individual_Class::DemandPhenotype_INDIVIDUALS(Species *species, Individual
74087408
// ploidy and callbacks as needed. It is very nice to have the top-level loop be over the chromosomes,
74097409
// so that each one can do a single timing for mutrun experiments.
74107410
int haplosome_index = 0;
7411+
bool local_doing_mutrun_experiments = species->DoingAnyMutationRunExperiments();
74117412

74127413
for (Chromosome *chromosome : species->Chromosomes())
74137414
{
7414-
if (species->DoingAnyMutationRunExperiments())
7415+
if (local_doing_mutrun_experiments)
74157416
chromosome->StartMutationRunExperimentClock();
74167417

74177418
switch (chromosome->Type())
@@ -7562,7 +7563,7 @@ void Individual_Class::DemandPhenotype_INDIVIDUALS(Species *species, Individual
75627563
}
75637564
}
75647565

7565-
if (species->DoingAnyMutationRunExperiments())
7566+
if (local_doing_mutrun_experiments)
75667567
chromosome->StopMutationRunExperimentClock("DemandPhenotype_INDIVIDUALS()");
75677568

75687569
haplosome_index += chromosome->IntrinsicPloidy();
@@ -7866,10 +7867,11 @@ void Individual_Class::DemandPhenotype_SUBPOP(Species *species, Subpopulation *s
78667867
// ploidy and callbacks as needed. It is very nice to have the top-level loop be over the chromosomes,
78677868
// so that each one can do a single timing for mutrun experiments.
78687869
int haplosome_index = 0;
7870+
bool local_doing_mutrun_experiments = species->DoingAnyMutationRunExperiments();
78697871

78707872
for (Chromosome *chromosome : species->Chromosomes())
78717873
{
7872-
if (species->DoingAnyMutationRunExperiments())
7874+
if (local_doing_mutrun_experiments)
78737875
chromosome->StartMutationRunExperimentClock();
78747876

78757877
for (int trait_indices_index = 0; trait_indices_index < trait_indices_count; trait_indices_index++)
@@ -8219,7 +8221,7 @@ void Individual_Class::DemandPhenotype_SUBPOP(Species *species, Subpopulation *s
82198221
}
82208222
}
82218223

8222-
if (species->DoingAnyMutationRunExperiments())
8224+
if (local_doing_mutrun_experiments)
82238225
chromosome->StopMutationRunExperimentClock("DemandPhenotype_SUBPOP()");
82248226

82258227
haplosome_index += chromosome->IntrinsicPloidy();

core/population.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,13 +1303,15 @@ void Population::EvolveSubpopulation(Subpopulation &p_subpop, bool p_mate_choice
13031303
bool recording_tree_sequence = species_.RecordingTreeSequence();
13041304
bool has_munge_callback = (p_modify_child_callbacks_present || p_recombination_callbacks_present || p_mutation_callbacks_present);
13051305
bool is_spatial = (species_.SpatialDimensionality() >= 1);
1306-
bool mutrun_exp_timing_per_individual = species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() > 1);
1306+
bool local_doing_mutrun_experiments = species_.DoingAnyMutationRunExperiments();
1307+
bool do_mutrun_exp_timing_per_individual = local_doing_mutrun_experiments && (species_.Chromosomes().size() > 1);
1308+
bool do_mutrun_exp_timing_once = local_doing_mutrun_experiments && (species_.Chromosomes().size() == 1);
13071309

13081310
bool (Subpopulation::*MungeIndividualCrossed_TEMPLATED)(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);
13091311
bool (Subpopulation::*MungeIndividualSelfed_TEMPLATED)(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);
13101312
bool (Subpopulation::*MungeIndividualCloned_TEMPLATED)(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);
13111313

1312-
if (mutrun_exp_timing_per_individual)
1314+
if (do_mutrun_exp_timing_per_individual)
13131315
{
13141316
if (pedigrees_enabled)
13151317
{
@@ -1593,7 +1595,7 @@ void Population::EvolveSubpopulation(Subpopulation &p_subpop, bool p_mate_choice
15931595
}
15941596

15951597
// refine the above choice with a custom version of optimizations for simple "A" and "H" cases
1596-
if (!mutrun_exp_timing_per_individual && !has_munge_callback && (species_.Chromosomes().size() == 1))
1598+
if (!do_mutrun_exp_timing_per_individual && !has_munge_callback && (species_.Chromosomes().size() == 1))
15971599
{
15981600
Chromosome *chromosome = species_.Chromosomes()[0];
15991601
ChromosomeType chromosome_type = chromosome->Type();
@@ -1807,7 +1809,7 @@ void Population::EvolveSubpopulation(Subpopulation &p_subpop, bool p_mate_choice
18071809
// are various ways that could potentially be cut down. (a) not measure in every tick, (b) stop measuring
18081810
// once you've settled down into stasis, (c) measure a subset of all reproductions. This should be done in
18091811
// future, but we're out of time for now.
1810-
if (species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() == 1))
1812+
if (do_mutrun_exp_timing_once)
18111813
species_.Chromosomes()[0]->StartMutationRunExperimentClock();
18121814

18131815
if (p_mate_choice_callbacks_present || p_modify_child_callbacks_present || p_recombination_callbacks_present || p_mutation_callbacks_present || p_type_s_DES_present)
@@ -2746,7 +2748,7 @@ void Population::EvolveSubpopulation(Subpopulation &p_subpop, bool p_mate_choice
27462748
// Mutrun experiment timing can be per-individual, per-chromosome, but that entails a lot of timing overhead.
27472749
// To avoid that overhead, in single-chromosome models we just time across the whole round of reproduction
27482750
// instead. Note that in this case we chose a template above for the Munge...() methods that does not time.
2749-
if (species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() == 1))
2751+
if (do_mutrun_exp_timing_once)
27502752
species_.Chromosomes()[0]->StopMutationRunExperimentClock("EvolveSubpopulation()");
27512753
}
27522754

core/species.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,7 @@ void Species::_ValidateNonNeutralCaches(const std::vector<slim_trait_index_t> &p
17231723
MutationBlock *mutation_block = mutation_block_;
17241724
Mutation *mut_block_ptr = mutation_block->mutation_buffer_;
17251725
const std::map<slim_objectid_t,MutationType*> &mut_types = MutationTypes();
1726+
bool local_doing_mutrun_experiments = DoingAnyMutationRunExperiments();
17261727

17271728
for (Chromosome *chromosome : chromosomes_)
17281729
{
@@ -1888,7 +1889,7 @@ void Species::_ValidateNonNeutralCaches(const std::vector<slim_trait_index_t> &p
18881889
int64_t mutations_cached = 0, mutations_omitted = 0, mutations_summarized = 0;
18891890
#endif
18901891

1891-
if (DoingAnyMutationRunExperiments()) chromosome->StartMutationRunExperimentClock();
1892+
if (local_doing_mutrun_experiments) chromosome->StartMutationRunExperimentClock();
18921893

18931894
int mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();
18941895

@@ -2077,7 +2078,7 @@ void Species::_ValidateNonNeutralCaches(const std::vector<slim_trait_index_t> &p
20772078
#endif
20782079
}
20792080

2080-
if (DoingAnyMutationRunExperiments()) chromosome->StopMutationRunExperimentClock("ValidateNonNeutralCaches()");
2081+
if (local_doing_mutrun_experiments) chromosome->StopMutationRunExperimentClock("ValidateNonNeutralCaches()");
20812082

20822083
#if SLIM_PROFILE_NONNEUTRAL_CACHES()
20832084
// FIXME MULTITRAIT: would be nice to use total_run_count in the profile output too!
@@ -5346,8 +5347,6 @@ void Species::MaintainTreeSequence(void)
53465347
void Species::EmptyGraveyard(void)
53475348
{
53485349
// Individuals end up in graveyard_ due to killIndividuals(); they get disposed of here.
5349-
// It's not necessary that FreeSubpopIndividual() be called on the correct subpopulation, really,
5350-
// but that API is at the Subpopulation level instead of in Species for efficiency, so...
53515350
for (Individual *individual : graveyard_)
53525351
individual->subpopulation_->FreeSubpopIndividual(individual);
53535352

@@ -5518,8 +5517,9 @@ void Species::nonWF_GenerateOffspring(void)
55185517
bool recording_tree_sequence = RecordingTreeSequence();
55195518
bool has_callbacks = ((reproduction_callbacks.size() > 0) || (modify_child_callbacks.size() > 0) || (recombination_callbacks.size() > 0) || (mutation_callbacks.size() > 0));
55205519
bool is_spatial = (SpatialDimensionality() >= 1);
5520+
bool local_doing_mutrun_experiments = DoingAnyMutationRunExperiments();
55215521

5522-
if (DoingAnyMutationRunExperiments())
5522+
if (local_doing_mutrun_experiments)
55235523
{
55245524
if (pedigrees_enabled)
55255525
{
@@ -6005,6 +6005,17 @@ void Species::nonWF_ViabilitySurvival(void)
60056005
population_.InvalidateMutationReferencesCache();
60066006
}
60076007

6008+
bool Species::DoingAnyMutationRunExperiments(void) const
6009+
{
6010+
// BCH 7/21/2026: We want to allow some operations to be done in the Eidos console that would normally
6011+
// be measured for mutrun experiments, so here we disable mutrun experiments when between ticks.
6012+
// NOTE: For this reason, doing_any_mutrun_experiments_ should not be consulted directly!
6013+
if (community_.CycleStage() == SLiMCycleStage::kStagePostCycle)
6014+
return false;
6015+
6016+
return doing_any_mutrun_experiments_;
6017+
}
6018+
60086019
void Species::FinishMutationRunExperimentTimings(void)
60096020
{
60106021
for (Chromosome *chromosome : chromosomes_)

core/species.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ class Species : public EidosDictionaryUnretained
327327

328328
// mutation run timing experiment configuration
329329
bool do_mutrun_experiments_ = true; // user-level flag in initializeSLiMOptions(); if false, experiments are never run
330-
bool doing_any_mutrun_experiments_ = false; // is any chromosome actually running mutation run timing experiments?
330+
bool doing_any_mutrun_experiments_ = false; // is any chromosome actually running mutation run timing experiments? DO NOT USE DIRECTLY!
331331

332332
// nucleotide-based models
333333
bool nucleotide_based_ = false;
@@ -709,7 +709,7 @@ class Species : public EidosDictionaryUnretained
709709

710710
inline __attribute__((always_inline)) bool UserWantsMutrunExperiments(void) const { return do_mutrun_experiments_; }
711711
inline __attribute__((always_inline)) void DoingMutrunExperimentsForChromosome(void) { doing_any_mutrun_experiments_ = true; }
712-
inline __attribute__((always_inline)) bool DoingAnyMutationRunExperiments(void) const { return doing_any_mutrun_experiments_; }
712+
bool DoingAnyMutationRunExperiments(void) const;
713713

714714
inline __attribute__((always_inline)) bool IsNucleotideBased(void) const { return nucleotide_based_; }
715715

core/subpopulation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10555,7 +10555,7 @@ EidosValue_SP Subpopulation::ExecuteMethod_removeSubpopulation(EidosGlobalString
1055510555

1055610556
// TIMING RESTRICTION
1055710557
if (community_.executing_species_ == &species_)
10558-
community_.EnforceTimingRestriction_EventBlockOnly("Subpopulation::ExecuteMethod_removeSubpopulation", "removeSubpopulation()", "");
10558+
community_.EnforceTimingRestriction_EventBlockOnly("Subpopulation::ExecuteMethod_removeSubpopulation", "removeSubpopulation()", ", when called on the currently executing species");
1055910559

1056010560
population_.RemoveSubpopulation(*this);
1056110561

0 commit comments

Comments
 (0)