matsim-org / matsim-libs

Multi-Agent Transport Simulation
www.matsim.org
489 stars 449 forks source link

ev: issues with ChargingHandler.notifyMobsimAfterSimStep #3545

Open sebhoerl opened 1 week ago

sebhoerl commented 1 week ago

I have a use case where I react on ChargingStartEvents using a simple event handler, and it is critical that timing is right. In particular, I collect various events in time step T and then process them in a MobsimEngine.doSimStep in time step T + 1. This way, we are sure to handle everything that happened in T at once and not have events arriving in parallel to the logic implemented in doSimStep. This is a common pattern that we use in various contribs (for instance, sharing).

Now for ChargingStartEvent this mechanism breaks, because the events are generated over several stations inside ChargingHandler.notifyMobsimAfterSimStep:

My conclusion from that would be:

kainagel commented 1 week ago

We had the same problem (with the charging handler, for the same reason) some other time. I would agree that moving it into the mobsim reduces the problem, since in the mobsim we have "physical" sequences of activities and in consequence should have correspondingly sequenced events. However, for this we need that "patches" of physics are on the same thread/CPU (i.e. both the vehicle and the charging station to which it connects). I am a big fan of such "physical patches", but pieces of matsim infrastructure go into a different direction. @paulheinr , @Janekdererste , @rakow , @mrieser: Maybe you want to take not of this issue for other parallel implementations we are working on?

michalmac commented 1 week ago

IIRC I was thinking about moving the whole "EV simulation" inside mobsim. It felt very natural. However, the biggest hurdle was the energy consumption part, where currently we listen to traffic/link entered/left events. Simulating charging inside mobsim and discharging outside it seems a bit fragile (with a high likelihood of running into some race conditions). As far as I remember, my conclusion was that it would be best to somehow plug in the energy discharging logic directly into QSim (i.e. not via events), so whenever a vehicle moves, its SoC gets immediately updated.

michalmac commented 1 week ago

I also do not like the feedback loop from events to back to simulation. For instance, vehicle events --> energy discharging events --> change in SOC which may impact Mobsim at this or next step (e.g. vehicle can or cannot travel the link because of negative SOC).

sebhoerl commented 1 week ago

FYI, I now have the following pattern which should work robustly in this kind of situations:

class MyMobsimEngine implements MobsimEngine, ChargingStartEventHandler, MobsimScopeEventHandler {
  // Event collection part

  private final List<ChargingStartEvent> chargingStartEvents = new LinkedList<>();

  @Override
  public void handleEvent(ChargingStartEvent event) {
    synchronized (chargingStartEvents) {
      chargingStartEvents.add(event);
    }
  }

  // Event processing part

  @Override
  public void doSimStep(double time) {
    processPersonDepartureEvents(time);
  }

  private void processPersonDepartureEvents(time) {
    synchronized (chargingStartEvents) {
      var iterator = chargingStartEvents.iterator();

      while (iterator.hasNext()) {
        ChargingStartEvent event = iterator.next();

        if (event.getTime() < time - 1.0) {
          iterator.remove();
          // do something with the event
        }
      }
    }
  }
}

The if (event.getTime() < time) is important in case the events of the previous or current iteration can arrive before and after calling processPersonDepartureEvents. And -1.0 is necessary for events that are thrown in an afterMobsim listener.

jfbischoff commented 1 week ago

IIRC I was thinking about moving the whole "EV simulation" inside mobsim. It felt very natural. However, the biggest hurdle was the energy consumption part, where currently we listen to traffic/link entered/left events. Simulating charging inside mobsim and discharging outside it seems a bit fragile (with a high likelihood of running into some race conditions). As far as I remember, my conclusion was that it would be best to somehow plug in the energy discharging logic directly into QSim (i.e. not via events), so whenever a vehicle moves, its SoC gets immediately updated.

I remenber our discussions about that. Keeping discharging out of the QSim has some advantages as well though, the handling is far more intuitive in a MATSim sense (we don't really care what's going on while a vehicle is on a link), and handling discharging every timestep is probably more intense in computational terms.

Apart from historic comments, I have no strong opinions on design changes 😄