Skip to content

Commit

Permalink
allow users to set a custom termination condition
Browse files Browse the repository at this point in the history
  • Loading branch information
RomainFranceschini committed Jul 11, 2019
1 parent e850132 commit f1176b9
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 26 deletions.
6 changes: 3 additions & 3 deletions spec/scenarios/sim_gen_spec.cr
Expand Up @@ -38,9 +38,9 @@ private module GeneratorScenario
gen.elapsed_values[i].should eq(Duration.new(0))
}

gen.output_calls.should eq(9)
gen.internal_calls.should eq(9)
gen.time.to_i.should eq(9)
gen.output_calls.should eq(10)
gen.internal_calls.should eq(10)
gen.time.to_i.should eq(10)
gen.elapsed_values.last.should eq(Duration.new(0))
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/scenarios/sim_ta_0_loop_spec.cr
Expand Up @@ -38,7 +38,7 @@ private module LoopScenario
describe "PDEVS simulation" do
it "allows ta(s)=0 loops" do
m = M.new :m
sim = Quartz::Simulation.new(m)
sim = Quartz::Simulation.new(m, loggers: Loggers.new(false))
sim.initialize_simulation
sim.step

Expand Down
56 changes: 34 additions & 22 deletions src/quartz/simulation.cr
Expand Up @@ -27,6 +27,7 @@ module Quartz
@run_validations : Bool
@model : CoupledModel
@time_next : Duration = Duration.new(0)
@termination_condition : Proc(TimePoint, CoupledModel, Bool)

delegate ready?, to: @status
delegate initialized?, to: @status
Expand All @@ -37,16 +38,23 @@ module Quartz
def initialize(model : Model, *,
@scheduler : Symbol = :binary_heap,
maintain_hierarchy : Bool = true,
duration : Duration = Duration::INFINITY,
duration : (Duration | TimePoint) = Duration::INFINITY,
@run_validations : Bool = false,
@notifier : Hooks::Notifier = Hooks::Notifier.new,
@loggers : Loggers = Loggers.new(true))
@final_vtime = if duration.infinite?
nil
else
TimePoint.new(duration.multiplier, duration.precision)
@final_vtime = case duration
when Duration
duration.infinite? ? nil : TimePoint.new(duration.multiplier, duration.precision)
when TimePoint
duration
end

@termination_condition = if ftime = @final_vtime
->(vtime : TimePoint, model : CoupledModel) { vtime > ftime.not_nil! }
else
->(vtime : TimePoint, model : CoupledModel) { false }
end

@model = case model
when AtomicModel, MultiComponent::Model
CoupledModel.new(:root_coupled_model) << model
Expand All @@ -61,6 +69,11 @@ module Quartz
end
end

# Set the termination condition
def termination_condition(&block : TimePoint, CoupledModel -> Bool)
@termination_condition = block
end

@[AlwaysInline]
protected def processor
@processor ||= begin
Expand All @@ -75,7 +88,6 @@ module Quartz
def inspect(io)
io << "<" << self.class.name << ": status=" << status.to_s(io)
io << ", time=" << virtual_time.to_s(io)
io << ", final_time=" << @final_vtime ? @final_vtime.to_s(io) : "INFINITY"
nil
end

Expand Down Expand Up @@ -169,7 +181,7 @@ module Quartz
private def begin_simulation
@start_time = Time.monotonic
@status = Status::Running
@loggers.info "Beginning simulation until time point: #{@final_vtime ? @final_vtime : "INFINITY"}"
@loggers.info "Beginning simulation"
@notifier.notify(Hooks::PRE_SIMULATION)
end

Expand Down Expand Up @@ -215,15 +227,19 @@ module Quartz
@time_next
when Status::Initialized, Status::Running
processor.advance by: @time_next
if @termination_condition.call(@virtual_time, @model)
end_simulation
return nil
end

if @loggers.any_debug?
@loggers.debug("Tick at #{virtual_time}, #{Time.monotonic - @start_time.not_nil!} secs elapsed.")
end

@time_next = processor.step(@time_next)
if @time_next.infinite?
end_simulation
elsif final = @final_vtime
end_simulation if @time_next >= (final - virtual_time)
end

end_simulation if @time_next.infinite?

@time_next
else
nil
Expand All @@ -239,15 +255,13 @@ module Quartz
begin_simulation
loop do
processor.advance by: @time_next
break if @termination_condition.call(@virtual_time, @model)

if @loggers.any_debug?
@loggers.debug("Tick at: #{virtual_time}, #{Time.monotonic - @start_time.not_nil!} secs elapsed.")
end
@time_next = processor.step(@time_next)
if @time_next.infinite?
break
elsif final = @final_vtime
break if @time_next >= (final - virtual_time)
end
break if @time_next.infinite?
end
end_simulation
when Status::Running
Expand All @@ -270,15 +284,13 @@ module Quartz
begin_simulation
loop do
processor.advance by: @time_next
break if @termination_condition.call(@virtual_time, @model)

if @loggers.any_debug?
@loggers.debug("Tick at: #{virtual_time}, #{Time.monotonic - @start_time.not_nil!} secs elapsed.")
end
@time_next = processor.step(@time_next)
if @time_next.infinite?
break
elsif final = @final_vtime
break if @time_next >= (final - virtual_time)
end
break if @time_next.infinite?
yield(@time_next)
end
end_simulation
Expand Down

0 comments on commit f1176b9

Please sign in to comment.