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

Unexpected 'release: not previously seized' #94

Closed
mmarks13 opened this issue May 5, 2017 · 11 comments
Closed

Unexpected 'release: not previously seized' #94

mmarks13 opened this issue May 5, 2017 · 11 comments

Comments

@mmarks13
Copy link

mmarks13 commented May 5, 2017

I'm encountering another instance of unexpected behavior. The code below seems to run fine at low volumes (e.g. Yearly_Case_Volume < 5000). However, when I overload the system with very high volumes, I get the 'release: not previously seized' error (see below). When this error occurs seems to be volume and capacity dependent. You can control volume and capacity with Yearly_Case_Volume and Mill_Capacity variables.

library(simmer)

#'#Define Case Paths
#############################################################################################################

#Trajectory to send signal to start Milling. 
#In real life milling starts at the end of the day and runs overnight. 
Milling_Start <- trajectory() %>%
  log_("Start_Milling") %>%
  send("Start_Milling")

#'##sub-paths for parts of the process with more detail or shared trajectories across materials
Milling_SubTraj <-   trajectory("Milling_SubTraj") %>%
  #When Start_Milling signal is sent, all cases in wait() will be sent here.
  trap("Start_Milling",
       handler =
         trajectory("Milling") %>%
         log_("Start_Milling_handler") %>%
         set_capacity("Mill",Mill_Capacity) %>% #temporarily set capacity equal to 50. Another way to do batching.
         log_("Done_Set_Mill_Capacity") %>%
         seize("Mill", 1) %>%
         log_("Done_Seize_Mill") %>%
         timeout(Mill_Timeout) %>%
         log_("Done_Mill_Timeout") %>%
         set_capacity("Mill",0) %>% #set capacity to zero to prevent more cases from moving through.
         log_("Done_Mill_capacity0") %>%
         release("Mill", 1) %>%
       log_("Done_release_mill") 
       ,interruptable = FALSE
  ) %>%
  #Upon a signal reception, the arrival stops the current waiting activity and executes the handler if provided. Then, the execution returns to the activity following the point of the interruption:
  log_("Start_Wait") %>%
  wait() %>%
  #if a case has gotten here, Milling is complete. Unsubscribe the case from the Start_Milling signal.
  untrap("Start_Milling") 
  log_(function(attrs) paste("done milling - material", attrs[["material"]],sep=''))


#'##Path for each material##
Material1 <- trajectory("Material1_Path") %>%
  set_attribute("material", 1) %>%
  log_("Entering Milling on Material1 trajectory")
  join(Milling_SubTraj)



Material2 <- trajectory("Material2_Path") %>%
  set_attribute("material", 2) %>%
  log_("Entering Milling on Material2 trajectory") %>%
  join(Milling_SubTraj)


Material3 <- trajectory("Material3") %>%
  set_attribute("material", 3) %>%
  log_("Entering Milling on Material3 trajectory") %>%
  join(Milling_SubTraj)



#'Overall Path
#'build overall path based on the pct of each material coming into the system. The case will go down a trajectory based on the material prob. 
Overall_Path <- trajectory() %>%
  #'branch to different materials
  branch(function() sample(c(1,2,3),1,replace=TRUE,prob= c(.33,.33,.33)),continue=c(T,T,T),
         Material1,
         Material2,
         Material3) 



#'#Run Simulation
#############################################################################################################
Yearly_Case_Volume <- 50000
Mill_Capacity <- 200

Yearly_Sim_Days <- 260
Daily_Sim_Hours <- 8
Cases_Per_Hour <- Yearly_Case_Volume/Yearly_Sim_Days/Daily_Sim_Hours
Inter_Arrival_Time <- 60/Cases_Per_Hour
runtime <- 10000 #minutes

env <- simmer()
env %>%
  add_resource("Mill", Mill_Capacity) %>%
  add_generator("Case", Overall_Path,function() rexp(1, rate = 1/Inter_Arrival_Time), mon = 2) %>%
  add_generator("Milling_Start", Milling_Start, at(Milling_Start_Times)) %>%
  run(runtime)

Output

> 3480: Case236: Done_Mill_Timeout
> 3480: Case236: Done_Mill_capacity0
> 3480: Case236: Done_release_mill
> 3480: Case236: Done_Mill_Timeout
> 3480: Case236: Done_Mill_capacity0
> 3480: Case236: Done_release_mill
> 3480: Case236: Done_Mill_Timeout
> 3480: Case236: Done_Mill_capacity0
> Error in run_(private$sim_obj, until) : 
  Mill: release: not previously seized
> In addition: Warning message:
  In run_(private$sim_obj, until) :
  `Case233`: leaving without releasing `Mill`
@Enchufa2
Copy link
Member

Enchufa2 commented May 5, 2017

I'm having trouble running your example, because there are missing variables and other problems. Please, check the code in a clean environment and fix it. Also, please, set a seed at the beginning (set.seed(1234), for instance) so that I can replicate the exact same error.

@mmarks13
Copy link
Author

mmarks13 commented May 5, 2017

Sorry. Probably should have cleared my environment before I tested it. Here you go. The seed doesn't seem to be working right; however, I was simply getting a slightly different version of the same error each time.

library(simmer)
Yearly_Case_Volume <- 50000
Mill_Capacity <- 200
set.seed(1234)



#'#Define Case Paths
#############################################################################################################

#Trajectory to send signal to start Milling. 
#In real life milling starts at the end of the day and runs overnight. 
Milling_Start <- trajectory() %>%
  log_("Start_Milling") %>%
  send("Start_Milling")

#'##sub-paths for parts of the process with more detail or shared trajectories across materials
Milling_SubTraj <-   trajectory("Milling_SubTraj") %>%
  #When Start_Milling signal is sent, all cases in wait() will be sent here.
  trap("Start_Milling",
       handler =
         trajectory("Milling") %>%
         log_("Start_Milling_handler") %>%
         set_capacity("Mill",Mill_Capacity) %>% #temporarily set capacity equal to a set number. Another way to do batching.
         log_("Done_Set_Mill_Capacity") %>%
         seize("Mill", 1) %>%
         log_("Done_Seize_Mill") %>%
         timeout(function(attrs){10*get_server_count(env,"Mill")}) %>%
         log_("Done_Mill_Timeout") %>%
         set_capacity("Mill",0) %>% #set capacity to zero to prevent more cases from moving through.
         log_("Done_Mill_capacity0") %>%
         release("Mill", 1) %>%
       log_("Done_release_mill") 
  ) %>%
  #Upon a signal reception, the arrival stops the current waiting activity and executes the handler if provided. Then, the execution returns to the activity following the point of the interruption:
  log_("Start_Wait") %>%
  wait() %>%
  #if a case has gotten here, Milling is complete. Unsubscribe the case from the Start_Milling signal.
  untrap("Start_Milling") 
  log_(function(attrs) paste("done milling - material", attrs[["material"]],sep=''))


#'##Path for each material##
Material1 <- trajectory("Material1_Path") %>%
  set_attribute("material", 1) %>%
  log_("Entering Milling on Material1 trajectory")
  join(Milling_SubTraj)



Material2 <- trajectory("Material2_Path") %>%
  set_attribute("material", 2) %>%
  log_("Entering Milling on Material2 trajectory") %>%
  join(Milling_SubTraj)


Material3 <- trajectory("Material3") %>%
  set_attribute("material", 3) %>%
  log_("Entering Milling on Material3 trajectory") %>%
  join(Milling_SubTraj)



#'Overall Path
#'build overall path based on the pct of each material coming into the system. The case will go down a trajectory based on the material prob. 
Overall_Path <- trajectory() %>%
  #'branch to different materials
  branch(function() sample(c(1,2,3),1,replace=TRUE,prob= c(.33,.33,.33)),continue=c(T,T,T),
         Material1,
         Material2,
         Material3) 



#'#Run Simulation
#############################################################################################################
Yearly_Sim_Days <- 260
Daily_Sim_Hours <- 8
Cases_Per_Hour <- Yearly_Case_Volume/Yearly_Sim_Days/Daily_Sim_Hours
Inter_Arrival_Time <- 60/Cases_Per_Hour
runtime <- 10000 #minutes
workday <- c(8*60, 16*60)
Milling_Start_Times <- seq(workday[2],runtime,1440)


env <- simmer()
env %>%
  add_resource("Mill", Mill_Capacity) %>%
  add_generator("Case", Overall_Path,function() rexp(1, rate = 1/Inter_Arrival_Time), mon = 2) %>%
  add_generator("Milling_Start", Milling_Start, at(Milling_Start_Times)) %>%
  run(runtime)

@Enchufa2
Copy link
Member

Enchufa2 commented May 6, 2017

Thanks, it runs correctly now and I get the error. Apparently, setting trap()'s interruptible=FALSE flag solves the issue.

@mmarks13
Copy link
Author

mmarks13 commented May 6, 2017

Thanks for the prompt reply. That worked for the code example I provided, but not my main code. I updated my example what some additions that recreates the problem.

I added queue_size = 0 to the Mill resource and a reject trajectory when you try to seize it.

library(simmer)
Yearly_Case_Volume <- 50000
Mill_Capacity <- 200
set.seed(1234)



#'#Define Case Paths
#############################################################################################################

#Trajectory to send signal to start Milling. 
#In real life milling starts at the end of the day and runs overnight. 
Milling_Start <- trajectory() %>%
  log_("Start_Milling") %>%
  send("Start_Milling")

#'##sub-paths for parts of the process with more detail or shared trajectories across materials
Milling_SubTraj <-   trajectory("Milling_SubTraj") %>%
  #When Start_Milling signal is sent, all cases in wait() will be sent here.
  trap("Start_Milling",
       handler =
         trajectory("Milling") %>%
         log_("Start_Milling_handler") %>%
         set_capacity("Mill",Mill_Capacity) %>% #temporarily set capacity equal to a set number. Another way to do batching.
         log_("Done_Set_Mill_Capacity") %>%
         seize("Mill", 1, reject= trajectory() %>%
                 log_("REJECTED") %>%
                 rollback(8),continue=T) %>%
         log_("Done_Seize_Mill") %>%
         timeout(function(attrs){10*get_server_count(env,"Mill")}) %>%
         log_("Done_Mill_Timeout") %>%
         set_capacity("Mill",0) %>% #set capacity to zero to prevent more cases from moving through.
         log_("Done_Mill_capacity0") %>%
         release("Mill", 1) %>%
       log_("Done_release_mill") 
       ,interruptible=FALSE
  ) %>%
  #Upon a signal reception, the arrival stops the current waiting activity and executes the handler if provided. Then, the execution returns to the activity following the point of the interruption:
  log_("Start_Wait") %>%
  wait() %>%
  #if a case has gotten here, Milling is complete. Unsubscribe the case from the Start_Milling signal.
  untrap("Start_Milling") 
  log_(function(attrs) paste("done milling - material", attrs[["material"]],sep=''))


#'##Path for each material##
Material1 <- trajectory("Material1_Path") %>%
  set_attribute("material", 1) %>%
  log_("Entering Milling on Material1 trajectory")
  join(Milling_SubTraj)



Material2 <- trajectory("Material2_Path") %>%
  set_attribute("material", 2) %>%
  log_("Entering Milling on Material2 trajectory") %>%
  join(Milling_SubTraj)


Material3 <- trajectory("Material3") %>%
  set_attribute("material", 3) %>%
  log_("Entering Milling on Material3 trajectory") %>%
  join(Milling_SubTraj)



#'Overall Path
#'build overall path based on the pct of each material coming into the system. The case will go down a trajectory based on the material prob. 
Overall_Path <- trajectory() %>%
  #'branch to different materials
  branch(function() sample(c(1,2,3),1,replace=TRUE,prob= c(.33,.33,.33)),continue=c(T,T,T),
         Material1,
         Material2,
         Material3) 



#'#Run Simulation
#############################################################################################################
Yearly_Sim_Days <- 260
Daily_Sim_Hours <- 8
Cases_Per_Hour <- Yearly_Case_Volume/Yearly_Sim_Days/Daily_Sim_Hours
Inter_Arrival_Time <- 60/Cases_Per_Hour
runtime <- 10000 #minutes
workday <- c(8*60, 16*60)
Milling_Start_Times <- seq(workday[2],runtime,1440)


env <- simmer()
env %>%
  add_resource("Mill", Mill_Capacity,queue_size = 0) %>%
  add_generator("Case", Overall_Path,function() rexp(1, rate = 1/Inter_Arrival_Time), mon = 2) %>%
  add_generator("Milling_Start", Milling_Start, at(Milling_Start_Times)) %>%
  run(runtime)

@Enchufa2
Copy link
Member

Enchufa2 commented May 6, 2017

The problem is the seize. You are rolling back only once per arrival (by default, times=1; BTW maybe times=Inf would be better), and you marked the reject trajectory with continue=TRUE. Therefore, the second time an arrival reaches this point and gets rejected, it doesn't roll back and continues to the release, hence the error.

Therefore, you have two options. If you want to roll back only once, you should set continue=FALSE. On the other hand, if you want to always roll back, you should set times=Inf.

@mmarks13
Copy link
Author

mmarks13 commented May 6, 2017

Thanks so much! Changing to times=Inf got me the results I was looking for.

@Enchufa2
Copy link
Member

Enchufa2 commented May 6, 2017

Also note that, in this simulation, arrivals have a single task, so you don't really need the handler. This is the same:

Milling_SubTraj <-   trajectory("Milling_SubTraj") %>%
  #When Start_Milling signal is sent, all cases in wait() will be sent here.
  trap("Start_Milling") %>%
  #Upon a signal reception, the arrival stops the current waiting activity and executes the handler if provided. Then, the execution returns to the activity following the point of the interruption:
  log_("Start_Wait") %>%
  wait() %>%
  log_("Start_Milling_handler") %>%
  set_capacity("Mill",Mill_Capacity) %>% #temporarily set capacity equal to a set number. Another way to do batching.
  log_("Done_Set_Mill_Capacity") %>%
  seize("Mill", 1, reject= trajectory() %>%
          log_("REJECTED") %>%
          rollback(8, times=Inf),continue=T) %>%
  log_("Done_Seize_Mill") %>%
  timeout(function(attrs){10*get_server_count(env,"Mill")}) %>%
  log_("Done_Mill_Timeout") %>%
  set_capacity("Mill",0) %>% #set capacity to zero to prevent more cases from moving through.
  log_("Done_Mill_capacity0") %>%
  release("Mill", 1) %>%
  log_("Done_release_mill")
  #if a case has gotten here, Milling is complete. Unsubscribe the case from the Start_Milling signal.
  untrap("Start_Milling") %>%
  log_(function(attrs) paste("done milling - material", attrs[["material"]],sep=''))

@Enchufa2 Enchufa2 closed this as completed May 6, 2017
@mmarks13
Copy link
Author

mmarks13 commented May 8, 2017

Oh interesting. Thanks for that. I had simply followed the example from the documentation.

@NatalieCZP
Copy link

NatalieCZP commented Oct 6, 2021

Hey I am having a similar problem with the rollback function. When running my Simulation I get the
Error: in [Timeout]->Release->[Log]: 'System' not previously seized

set.seed(41)

# 5 subruns are conducted
Sim_Roles_NoSchedule <-lapply(1:5, function(i) {
  
  RepairEnv <- simmer("RepairSimulation")
  
  # Define Trajectory
  RepairTraj <- trajectory() %>%
    
    # In the following, all activities and choices are defined. Attributes are set as necessary input for the event log
    
    # Register
    set_attribute("Activity_id",1) %>%
    seize("System",1) %>%
    timeout(0) %>%
    release("System",1) %>%
    log_("Registered") %>%
    
    # Analyze Defect
    set_attribute("Activity_id",2) %>%
    seize("Tester",1) %>%
    timeout(function() {round(runif(1,5,10))}) %>%
    release("Tester",1) %>%
    log_("Repair tested") %>%
    
    # Repair Complex or Simple? --> Define Branch probabilities
    branch (option = function() {round(ifelse(runif(1,0,100)<43.88033,1,2))},
            continue=TRUE, 
            
            # Repair Simple
            trajectory() %>%
              set_attribute("Activity_id",3) %>%
              seize("SolverS",1) %>%
              set_attribute("numberRepair.simple",1,mod="+", init=0) %>%
              timeout(function() {round(runif(1,5,20))}) %>%
              release("SolverS",1) %>%
              log_ (function() paste("Repair Simple done, Repair No.:", get_attribute(RepairEnv, "numberRepair.simple")))  %>%
              
              # Test Repair (Repair Simple)
              set_attribute("Activity_id",5) %>%
              seize("Tester",1) %>%
              timeout(function() {round(runif(1,5,10))}) %>%
              release("Tester",1) %>%
              log_("Repair Tested (Simple)") %>% 
              
              # Restart Repair or inform User? --> Define Branch probabilities
              branch (option = function() {round(ifelse(runif(1,0,100)<34.6496,1,0))}, continue=TRUE,
                      # Restart Repair
                      trajectory() %>%
                        set_attribute("Activity_id",6) %>%
                        seize("System", 1) %>%
                        timeout(0) %>%
                        release("System", 1) %>%
                        rollback(24, times = Inf)
              ),
            
            # Repair Complex
            trajectory() %>%
              set_attribute("Activity_id",4) %>%
              seize("SolverC",1) %>%
              set_attribute("numberRepair.complex",1,mod="+", init=0) %>%
              timeout(function() {round(runif(1,10,40))}) %>%
              release("SolverC",1) %>%
              log_ (function() paste("Repair Complex done, Repair No.:", get_attribute(RepairEnv, "numberRepair.complex")))  %>%
              
              # Test Repair (Repair Complex)
              set_attribute("Activity_id",5) %>%
              seize("Tester",1) %>%
              timeout(function() {round(runif(1,5,10))}) %>%
              release("Tester",1) %>%
              log_("Repair Tested (Complex)") %>%   
              
              # Restart Repair or inform User? --> Define Branch probabilities
              branch (option = function() {round(ifelse(runif(1,0,100)<12.1547,1,0))}, continue=TRUE,
                      
                      #Restart Repair
                      trajectory() %>%
                        set_attribute("Activity_id",6) %>%
                        seize("System", 1) %>%
                        timeout(0) %>%
                        release("System", 1)  %>%
                        rollback(24, times =Inf) 
              )
    ) %>%  # (End of branch Repair Complex or Repair Simple)
    
    # Inform User
    set_attribute("Activity_id",7) %>%
    seize("System", 1) %>%
    timeout(0) %>%
    release("System", 1)   %>%
    log_ ("User Informed")  %>%
    
    
    # Archive Repair
    set_attribute("Activity_id",8) %>%
    seize("System", 1) %>%
    timeout(0) %>%
    release("System", 1)   %>%
    log_ ("Repair Archived")
  
  # End of Trajectory
  
  
  # Define resources and generator
  RepairEnv%>%
    add_resource("System", capacity = 1) %>%
    add_resource("Tester", capacity=6) %>%
    add_resource("SolverS",capacity= 3) %>%
    add_resource("SolverC", capacity= 3) %>%
    add_generator("RepairCase_", RepairTraj,distribution = function() rexp(1, rate=0.0331629585), mon=2) %>%
    run(until=10080)
})

@Enchufa2
Copy link
Member

Enchufa2 commented Oct 6, 2021

I recommend to print the trajectory. It reveals where the rollback is pointing:

print(RepairTraj)
#> trajectory: anonymous, 55 activities
#> [snip]
#>     { Activity: Rollback     | amount: 24 (Release), times: -1 }
#> [snip]

So it's pointing to the wrong place (the release activity, instead of seize). It's even easier if you plot the trajectory. Try this and you'll see:

library(simmer.plot)
plot(RepairTraj)

I think you missed the branches. I.e., this:

trajectory() %>%
  timeout(1) %>%
  branch(
    function() 1, TRUE,
    trajectory() %>%
      rollback(1)
  )
#> trajectory: anonymous, 3 activities
#> { Activity: Timeout      | delay: 1 }
#> { Activity: Branch       | option: function() }
#>   Fork 1, continue,  trajectory: anonymous, 1 activities
#>   { Activity: Rollback     | amount: 1 (Branch), times: -1 }

points back to the branch, as you can see. You need to go back 2 activities in order to point to the timeout:

trajectory() %>%
  timeout(1) %>%
  branch(
    function() 1, TRUE,
    trajectory() %>%
      rollback(2)
  )
#> trajectory: anonymous, 3 activities
#> { Activity: Timeout      | delay: 1 }
#> { Activity: Branch       | option: function() }
#>   Fork 1, continue,  trajectory: anonymous, 1 activities
#>   { Activity: Rollback     | amount: 2 (Timeout), times: -1 }

@NatalieCZP
Copy link

Thank you, I hadn't understand before what is considered an activity in the trajectory. That was of great help!

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