From add34b1b598f05b16ea8b6bf1cb74d83b799d8ef Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Thu, 8 Oct 2026 16:13:48 +0700 Subject: [PATCH 01/12] Batch: run simulations autonomously and fix until condition, thread leaks, status and reload Each batch simulation now runs on its own thread and is stopped by its own 'until' condition. Finished simulations are collected and replaced immediately and their runner threads terminate. Fixes #198, #282, #325, #358, #199. Implements #418. --- .../gama/api/runtime/GeneralSynchronizer.java | 2 - .../gama/api/runtime/ISimulationRunner.java | 23 ++- .../gama/api/runtime/SimulationRunner.java | 134 +++++++++++---- .../core/simulation/SimulationPopulation.java | 21 +++ .../src/gama/extension/batch/BatchAgent.java | 162 ++++++++++-------- 5 files changed, 234 insertions(+), 108 deletions(-) diff --git a/gama.api/src/gama/api/runtime/GeneralSynchronizer.java b/gama.api/src/gama/api/runtime/GeneralSynchronizer.java index 1cf56d2997..edd0f73459 100644 --- a/gama.api/src/gama/api/runtime/GeneralSynchronizer.java +++ b/gama.api/src/gama/api/runtime/GeneralSynchronizer.java @@ -157,7 +157,6 @@ public boolean acquire() { semaphore.acquire(); return true; } catch (InterruptedException e) { - e.printStackTrace(); Thread.currentThread().interrupt(); return false; } @@ -218,7 +217,6 @@ public boolean acquire(final int n) { semaphore.acquire(n); return true; } catch (InterruptedException e) { - e.printStackTrace(); Thread.currentThread().interrupt(); return false; } diff --git a/gama.api/src/gama/api/runtime/ISimulationRunner.java b/gama.api/src/gama/api/runtime/ISimulationRunner.java index 3fdd4da623..a13318f648 100644 --- a/gama.api/src/gama/api/runtime/ISimulationRunner.java +++ b/gama.api/src/gama/api/runtime/ISimulationRunner.java @@ -11,6 +11,9 @@ package gama.api.runtime; import java.util.Set; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Predicate; import gama.api.kernel.simulation.ISimulationAgent; @@ -138,4 +141,22 @@ public interface ISimulationRunner { */ boolean hasSimulations(); -} \ No newline at end of file + /** + * Lets an already added simulation run on its own thread, without any synchronization with the other simulations: + * it steps as many times as needed until {@code isOver} is true, then {@code onOver} is called (from the + * simulation's thread) and the thread terminates. The simulation is not taken into account by {@link #step()} + * anymore. + * + * @param agent + * a simulation previously added with {@link #add(ISimulationAgent)} + * @param isOver + * evaluated after each step (and in case of an error); true when the simulation must stop + * @param isPaused + * evaluated before each step; the simulation waits as long as it is true (unless it is over) + * @param onOver + * called once, when the simulation is over + */ + void runAutonomously(ISimulationAgent agent, Predicate isOver, BooleanSupplier isPaused, + Consumer onOver); + +} diff --git a/gama.api/src/gama/api/runtime/SimulationRunner.java b/gama.api/src/gama/api/runtime/SimulationRunner.java index 118a4146bf..de1dd4da72 100644 --- a/gama.api/src/gama/api/runtime/SimulationRunner.java +++ b/gama.api/src/gama/api/runtime/SimulationRunner.java @@ -17,12 +17,16 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Predicate; import gama.api.kernel.agent.IPopulation; import gama.api.kernel.simulation.ISimulationAgent; import gama.api.kernel.species.IExperimentSpecies; import gama.api.runtime.GamaExecutorService.Caller; import gama.dev.DEBUG; +import gama.dev.THREADS; /** * Default implementation of {@link ISimulationRunner} for managing concurrent simulation execution. @@ -169,51 +173,111 @@ private SimulationRunner(final int concurrency) { */ @Override public void remove(final ISimulationAgent agent) { - if (runnables.remove(agent) != null) { activeCount.decrementAndGet(); } + final Thread t = runnables.remove(agent); + if (t == null) return; + // Autonomous simulations have already been taken out of the count + if (!(t instanceof SimulationThread st) || st.autonomy == null) { activeCount.decrementAndGet(); } + // A thread idling on the semaphore would otherwise never terminate (see issues #198 and #282) + if (t instanceof SimulationThread st && st.waiting) { st.interrupt(); } + } + + /** A dedicated thread running the steps of one simulation, which can be woken up when it is removed. */ + private final class SimulationThread extends Thread { + + /** The agent. */ + private final ISimulationAgent agent; + + /** True while the thread is idle, waiting for the permission to step. */ + volatile boolean waiting; + + /** Set when the simulation must run on its own, without synchronization. */ + volatile Autonomy autonomy; + + /** + * Instantiates a new simulation thread. + * + * @param agent + * the agent + */ + SimulationThread(final ISimulationAgent agent) { + super("Thread of " + agent.getName()); + this.agent = agent; + setDaemon(true); + } + + /** Steps the simulation as fast as possible until it is over. */ + private void runFreely(final Autonomy a) { + boolean over = false; + while (!over && !shutdown && runnables.get(agent) == this) { + try { + while (a.isPaused.getAsBoolean() && !a.isOver.test(agent) && !shutdown) { THREADS.WAIT(10); } + if (!a.isOver.test(agent) && !shutdown) { agent.step(); } + } catch (Throwable tg) { + EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); + } + over = agent.dead() || a.isOver.test(agent); + } + if (!shutdown && runnables.get(agent) == this) { a.onOver.accept(agent); } + } + + @Override + public void run() { + while (!shutdown && !agent.dead() && runnables.get(agent) == this) { + waiting = true; + final boolean acquired = autonomy != null || simulationsSemaphore.acquire(); + waiting = false; + if (autonomy != null) { + Thread.interrupted(); + runFreely(autonomy); + return; + } + if (!acquired) { break; } + // Recheck after waking up: dispose() may have released the permit just to + // unblock this thread for shutdown — we must not step a dead/cleared runner. + if (shutdown || agent.dead()) { break; } + try { + agent.step(); + } catch (Throwable tg) { + EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); + } finally { + // Released whatever the outcome: a step that throws still consumed the permit granted by + // step(), which would otherwise wait for it forever. + experimentSemaphore.release(); + } + } + } + } + + /** The way an autonomous simulation is run. */ + private record Autonomy(Predicate isOver, BooleanSupplier isPaused, + Consumer onOver) {} + + @Override + public void runAutonomously(final ISimulationAgent agent, final Predicate isOver, + final BooleanSupplier isPaused, final Consumer onOver) { + if (!(runnables.get(agent) instanceof SimulationThread st)) return; + // The simulation does not take part in the synchronized steps anymore + activeCount.decrementAndGet(); + st.autonomy = new Autonomy(isOver, isPaused, onOver); + // The thread is idle (or about to be) on the semaphore: wake it up so that it notices its new mode + st.interrupt(); } /** - * Adds a simulation agent to the runner and starts its dedicated execution thread. - * - *

- * Creates a new thread for the simulation that will: - *

- *
    - *
  1. Wait for a permit from simulationsSemaphore
  2. - *
  3. Execute the simulation's step
  4. - *
  5. Release a permit to experimentSemaphore
  6. - *
  7. Repeat until the simulation dies or the runner shuts down
  8. - *
+ * Adds a simulation agent to the runner and starts its dedicated execution thread, which waits for a permit, + * steps the simulation, signals the experiment, and repeats until the simulation dies, is removed or the runner + * shuts down. * * @param agent * the simulation agent to add */ @Override public void add(final ISimulationAgent agent) { - Thread t = new Thread("Thread of " + agent.getName()) { - @Override - public void run() { - while (!shutdown && !agent.dead()) { - // DEBUG.OUT("Waiting for " + agent); - if (!simulationsSemaphore.acquire()) { break; } - // Recheck after waking up: dispose() may have released the permit just to - // unblock this thread for shutdown — we must not step a dead/cleared runner. - if (shutdown || agent.dead()) { break; } - try { - agent.step(); - } catch (Throwable tg) { - EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); - } finally { - // Released whatever the outcome: a step that throws still consumed the permit granted by - // step(), which would otherwise wait for it forever. - experimentSemaphore.release(); - } - } - } - }; - t.start(); + final Thread t = new SimulationThread(agent); + // Registered before starting, as the thread checks that it is still registered runnables.put(agent, t); activeCount.incrementAndGet(); + t.start(); } /** @@ -236,6 +300,8 @@ public void run() { @Override public void step() { // DEBUG.OUT("Releasing to all simulations"); + // Dead simulations never consume permits: counting them would block the experiment forever + for (final ISimulationAgent sim : runnables.keySet()) { if (sim.dead()) { remove(sim); } } int nb = activeCount.get(); simulationsSemaphore.release(nb); // If the experiment thread is interrupted while waiting, abort the step. diff --git a/gama.core/src/gama/core/simulation/SimulationPopulation.java b/gama.core/src/gama/core/simulation/SimulationPopulation.java index 06d4c5c73c..b0797d956e 100644 --- a/gama.core/src/gama/core/simulation/SimulationPopulation.java +++ b/gama.core/src/gama/core/simulation/SimulationPopulation.java @@ -14,6 +14,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Predicate; import gama.annotations.constants.IKeyword; import gama.api.GAMA; @@ -281,6 +284,24 @@ public void unscheduleSimulation(final ISimulationAgent sim) { runner.remove(sim); } + /** + * Lets a scheduled simulation run on its own thread, not synchronized with the other simulations, until it is + * over. + * + * @param sim + * a scheduled simulation + * @param isOver + * tells when the simulation must stop + * @param isPaused + * tells if the simulation should wait before its next step + * @param onOver + * called (from the simulation's thread) when the simulation is over + */ + public void runAutonomously(final ISimulationAgent sim, final Predicate isOver, + final BooleanSupplier isPaused, final Consumer onOver) { + runner.runAutonomously(sim, isOver, isPaused, onOver); + } + /** * Gets the number of active stepables. * diff --git a/gama.extension.batch/src/gama/extension/batch/BatchAgent.java b/gama.extension.batch/src/gama/extension/batch/BatchAgent.java index 76052f6ba3..962ecfa6bb 100644 --- a/gama.extension.batch/src/gama/extension/batch/BatchAgent.java +++ b/gama.extension.batch/src/gama/extension/batch/BatchAgent.java @@ -15,6 +15,14 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.IntSupplier; +import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.DoubleStream; import gama.annotations.doc; @@ -47,7 +55,6 @@ import gama.core.experiment.parameters.ParameterAdapter; import gama.core.experiment.parameters.ParametersSet; import gama.core.simulation.SimulationPopulation; -import gama.dev.THREADS; import gama.extension.batch.exploration.AExplorationAlgorithm; import gama.extension.batch.exploration.Exploration; import gama.extension.batch.optimization.AOptimizationAlgorithm; @@ -79,6 +86,9 @@ public class BatchAgent extends ExperimentAgent implements IExperimentAgent.Batc /** The run number. */ private int runNumber; + /** The number of simulations that have finished since the beginning of the batch. */ + private volatile int finishedSimulations; + /** The current solution. */ ParametersSet currentSolution; @@ -363,7 +373,6 @@ private ISimulationAgent createSimulation(final Map sim, // LinkedHashSet sols_u = new LinkedHashSet<>(sols); for (ParametersSet sol : sols) { for (int i = 0; i < getSeeds().length; i++) { - runNumber = runNumber + 1; Map sim = new HashMap<>(); sim.put("parameters", sol); sim.put("seed", getSeeds()[i]); @@ -371,46 +380,20 @@ private ISimulationAgent createSimulation(final Map sim, } } - int nb = Math.min(sims.size(), numberOfCores); - - List> simsToRun = new ArrayList<>(); - - for (int i = 0; i < nb; i++) { simsToRun.add(sims.remove(0)); } - Map simToParameter = GamaMapFactory.create(); - Iterator> it = simsToRun.iterator(); - while (it.hasNext()) { createSimulation(it.next(), simToParameter); } - while (pop.hasScheduledSimulations() && !dead) { - for (final ISimulationAgent agent : new ArrayList<>(pop.getRunningSimulations())) { - agent.step(); - ParametersSet ps = simToParameter.get(agent); - currentSolution = new ParametersSet(ps); - - // test the condition first in case it is paused - final boolean stopConditionMet = dead - || Cast.asBool(agent.getScope(), agent.getScope().evaluate(stopCondition, agent).getValue()); - final boolean mustStop = stopConditionMet || agent.dead(); - // AD -- removed because it would prevent simulations from running if 'do pause' was called in the - // experiment - // || agent.getScope().isPaused(); - if (mustStop) { - pop.unscheduleSimulation(agent); - // pop.remove(agent); - IMap localRes = manageOutputAndCloseSimulation(agent, ps, false, simDispose); - - if (!res.containsKey(ps)) { res.put(ps, GamaMapFactory.create()); } - localRes.forEach((output, obj) -> { - if (!res.get(ps).containsKey(output)) { res.get(ps).put(output, GamaListFactory.create()); } - res.get(ps).get(output).add(obj); - }); - - if (!sims.isEmpty()) { createSimulation(sims.remove(0), simToParameter); } - - } - } - if (!dead) { informStatus(pop, sims.size()); } - // We then verify that the front scheduler has not been paused - while (getSpecies().getController().isPaused() && !dead) { THREADS.WAIT(10); } - } + final Map simToParameter = GamaMapFactory.create(); + runSimulations(pop, numberOfCores, () -> { + if (sims.isEmpty()) return null; + return createSimulation(sims.remove(0), simToParameter); + }, sims::size, agent -> { + final ParametersSet ps = simToParameter.get(agent); + currentSolution = new ParametersSet(ps); + final IMap localRes = manageOutputAndCloseSimulation(agent, ps, false, simDispose); + if (!res.containsKey(ps)) { res.put(ps, GamaMapFactory.create()); } + localRes.forEach((output, obj) -> { + if (!res.get(ps).containsKey(output)) { res.get(ps).put(output, GamaListFactory.create()); } + res.get(ps).get(output).add(obj); + }); + }); // When the simulations are finished, we give a chance to the outputs of // the experiment and the experiment @@ -519,29 +502,12 @@ public Map> launchSimulationsWithSingleParametersSet(final int numberOfCores = pop.getMaxNumberOfConcurrentSimulations(); if (numberOfCores == 0) { numberOfCores = 1; } - int repeatIndex = 0; - while (repeatIndex < getSeeds().length && !dead) { - for (int coreIndex = 0; coreIndex < numberOfCores; coreIndex++) { - runNumber = runNumber + 1; - - setSeed(getSeeds()[repeatIndex]); - createSimulation(currentSolution, true); - repeatIndex++; - if (repeatIndex == getSeeds().length || dead) { break; } - } - while (pop.hasScheduledSimulations() && !dead) { - for (final ISimulationAgent sim : new ArrayList<>(pop.getRunningSimulations())) { - sim.step(); - final boolean stopConditionMet = - dead || Cast.asBool(sim.getScope(), sim.getScope().evaluate(stopCondition, sim).getValue()); - if (stopConditionMet || sim.dead()) { - processFinishedSimulation(sim, outputs); - } - } - if (!dead) { informStatus(pop, repeatIndex); } - while (getSpecies().getController().isPaused() && !dead) { THREADS.WAIT(10); } - } - } + final int[] repeatIndex = { 0 }; + runSimulations(pop, numberOfCores, () -> { + if (repeatIndex[0] >= getSeeds().length) return null; + setSeed(getSeeds()[repeatIndex[0]++]); + return createSimulation(currentSolution, true); + }, () -> getSeeds().length - repeatIndex[0], sim -> processFinishedSimulation(sim, outputs)); super.step(getScope()); if (dead) return outputs; @@ -553,18 +519,69 @@ public Map> launchSimulationsWithSingleParametersSet(final return outputs; } + /** + * Runs simulations, at most {@code concurrency} at a time. Each simulation runs on its own thread, without waiting + * for the others, until its own stop condition is met; it is then collected and replaced by a new one. + * + * @param pop + * the simulation population + * @param concurrency + * the maximum number of simulations running at the same time + * @param factory + * creates (and schedules) the next simulation to run, or returns null when there are none left + * @param remaining + * gives the number of simulations that are still to be created + * @param collector + * called, from the experiment thread, for each finished simulation + */ + private void runSimulations(final SimulationPopulation pop, final int concurrency, + final Supplier factory, final IntSupplier remaining, + final Consumer collector) { + final BlockingQueue finished = new LinkedBlockingQueue<>(); + final Predicate isOver = sim -> dead || sim.dead() + || Cast.asBool(sim.getScope(), sim.getScope().evaluate(stopCondition, sim).getValue()); + final BooleanSupplier isPaused = () -> getSpecies().getController().isPaused(); + int running = 0; + try { + while (!dead) { + ISimulationAgent sim; + while (running < concurrency && (sim = factory.get()) != null) { + runNumber++; + pop.runAutonomously(sim, isOver, isPaused, finished::add); + running++; + } + if (running == 0) { break; } + informStatus(pop, remaining.getAsInt()); + sim = finished.poll(100, TimeUnit.MILLISECONDS); + if (sim == null) { continue; } + running--; + pop.unscheduleSimulation(sim); + finishedSimulations++; + collector.accept(sim); + } + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + // Whatever the reason we leave (end, death, interruption), no simulation thread should remain + for (final ISimulationAgent sim : new ArrayList<>(pop.getRunningSimulations())) { + pop.unscheduleSimulation(sim); + } + } + } + /** * Inform status. * * @param pop * the pop - * @param repeatIndex - * the repeat index + * @param waiting + * the number of simulations not yet started */ - private void informStatus(final SimulationPopulation pop, final int repeatIndex) { - getScope().getGui().getStatus().setStatus("Run " + runNumber + " | " + repeatIndex + "/" + seeds.length - + " simulations (using " + pop.getNumberOfActiveThreads() + " threads)", IStatusMessage.SIMULATION_ICON, - null); + private void informStatus(final SimulationPopulation pop, final int waiting) { + getScope().getGui().getStatus() + .setStatus(finishedSimulations + " simulations finished | " + pop.getRunningSimulations().size() + + " running | " + waiting + " waiting (using " + pop.getMaxNumberOfConcurrentSimulations() + + " threads)", IStatusMessage.SIMULATION_ICON, null); getScope().getGui().getStatus().updateExperimentStatus(); } @@ -661,6 +678,9 @@ public void closeSimulations(final boolean andLeaveExperimentPerspective) { // We interrupt the simulation scope directly (as it cannot be // interrupted by the global scheduler) if (getSimulation() != null) { getSimulation().getScope().setDisposeStatus(); } + // When reloading, the views (including those of the 'permanent' section) must be closed, otherwise the new + // experiment opens its own next to the old ones (Issue #199). Not done on a simple reset between runs. + if (getSpecies().isReloading()) { getScope().getGui().closeSimulationViews(getScope(), false, true); } } @Override From 39eb4a3dddd5583a3d4753315e6a3772140ab9d5 Mon Sep 17 00:00:00 2001 From: Alexis Drogoul Date: Thu, 8 Oct 2026 16:31:11 +0700 Subject: [PATCH 02/12] Add exception handling for agent status check Handle exceptions when checking agent status and set 'over' accordingly. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- gama.api/src/gama/api/runtime/SimulationRunner.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gama.api/src/gama/api/runtime/SimulationRunner.java b/gama.api/src/gama/api/runtime/SimulationRunner.java index de1dd4da72..da8b9f559c 100644 --- a/gama.api/src/gama/api/runtime/SimulationRunner.java +++ b/gama.api/src/gama/api/runtime/SimulationRunner.java @@ -215,7 +215,11 @@ private void runFreely(final Autonomy a) { } catch (Throwable tg) { EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); } +try { over = agent.dead() || a.isOver.test(agent); + } catch (final Throwable tg) { + EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); + over = true; } if (!shutdown && runnables.get(agent) == this) { a.onOver.accept(agent); } } From 3f2689941154b42cec097f6b02fd776a125278bb Mon Sep 17 00:00:00 2001 From: Alexis Drogoul Date: Thu, 8 Oct 2026 16:32:02 +0700 Subject: [PATCH 03/12] Refactor simulation loop to check runnables condition Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- gama.api/src/gama/api/runtime/SimulationRunner.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gama.api/src/gama/api/runtime/SimulationRunner.java b/gama.api/src/gama/api/runtime/SimulationRunner.java index da8b9f559c..d5c01c511a 100644 --- a/gama.api/src/gama/api/runtime/SimulationRunner.java +++ b/gama.api/src/gama/api/runtime/SimulationRunner.java @@ -210,8 +210,9 @@ private void runFreely(final Autonomy a) { boolean over = false; while (!over && !shutdown && runnables.get(agent) == this) { try { - while (a.isPaused.getAsBoolean() && !a.isOver.test(agent) && !shutdown) { THREADS.WAIT(10); } - if (!a.isOver.test(agent) && !shutdown) { agent.step(); } + while (runnables.get(agent) == this && a.isPaused.getAsBoolean() && !a.isOver.test(agent) + && !shutdown) { THREADS.WAIT(10); } + if (runnables.get(agent) == this && !a.isOver.test(agent) && !shutdown) { agent.step(); } } catch (Throwable tg) { EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); } From c49c5c95ad7dfdbd7156ee50f7e6c61976484fa0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 8 Oct 2026 09:34:06 +0000 Subject: [PATCH 04/12] Count registered autonomous simulations Co-authored-by: AlexisDrogoul <579256+AlexisDrogoul@users.noreply.github.com> --- gama.api/src/gama/api/runtime/SimulationRunner.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/gama.api/src/gama/api/runtime/SimulationRunner.java b/gama.api/src/gama/api/runtime/SimulationRunner.java index d5c01c511a..cc4a7d21c5 100644 --- a/gama.api/src/gama/api/runtime/SimulationRunner.java +++ b/gama.api/src/gama/api/runtime/SimulationRunner.java @@ -341,19 +341,12 @@ public void dispose() { public Set getStepable() { return runnables.keySet(); } /** - * Returns the number of active simulation threads. - * - *

- * Uses a dedicated {@link AtomicInteger} counter maintained by {@link #add(ISimulationAgent)} and - * {@link #remove(ISimulationAgent)} rather than calling {@code ConcurrentHashMap.size()} (which is O(n)) on - * every simulation cycle. The atomic counter also ensures that concurrent calls to {@code add}, {@code remove}, - * and {@link #step()} always observe a consistent count. - *

+ * Returns the number of simulation threads currently registered with this runner. * * @return the count of simulations currently registered */ @Override - public int getActiveThreads() { return activeCount.get(); } + public int getActiveThreads() { return runnables.size(); } /** * Checks whether this runner has any active simulations. @@ -362,7 +355,7 @@ public void dispose() { */ @Override public boolean hasSimulations() { - return activeCount.get() > 0; + return !runnables.isEmpty(); } } From 9725080474e8796938cd99925b7d9195fbffb25b Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Thu, 8 Oct 2026 19:50:33 +0700 Subject: [PATCH 05/12] Update SimulationRunner.java --- .../gama/api/runtime/SimulationRunner.java | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/gama.api/src/gama/api/runtime/SimulationRunner.java b/gama.api/src/gama/api/runtime/SimulationRunner.java index cc4a7d21c5..52b8118a58 100644 --- a/gama.api/src/gama/api/runtime/SimulationRunner.java +++ b/gama.api/src/gama/api/runtime/SimulationRunner.java @@ -30,13 +30,13 @@ /** * Default implementation of {@link ISimulationRunner} for managing concurrent simulation execution. - * + * *

- * SimulationRunner coordinates the parallel execution of multiple simulation agents within a GAMA experiment. It uses - * a thread-per-simulation model where each simulation runs in its own dedicated thread, synchronized by semaphores to + * SimulationRunner coordinates the parallel execution of multiple simulation agents within a GAMA experiment. It uses a + * thread-per-simulation model where each simulation runs in its own dedicated thread, synchronized by semaphores to * ensure coordinated stepping. *

- * + * *

* Architecture: *

@@ -52,11 +52,11 @@ * complete *
  • Concurrency level is determined by experiment configuration and preferences
  • * - * + * *

    * Execution flow: *

    - * + * *
      * 1. Experiment calls step()
      * 2. step() releases N permits to simulationsSemaphore (N = number of simulations)
    @@ -65,27 +65,27 @@
      * 5. step() acquires N permits from experimentSemaphore (blocks until all done)
      * 6. step() returns to experiment, all simulations synchronized
      * 
    - * + * *

    * Usage example (typically internal): *

    - * + * *
      * IPopulation simPop = experiment.getSimulationPopulation();
      * SimulationRunner runner = SimulationRunner.of(simPop);
    - * 
    + *
      * // Add simulations
      * runner.add(simulation1);
      * runner.add(simulation2);
    - * 
    + *
      * // Run synchronized steps
      * while (!stopped) {
      * 	runner.step(); // All simulations execute one step
      * }
    - * 
    + *
      * runner.dispose();
      * 
    - * + * * @see ISimulationRunner * @see GeneralSynchronizer * @see ISimulationAgent @@ -104,7 +104,7 @@ public class SimulationRunner implements ISimulationRunner { /** Synchronizer signaling to the experiment when simulations complete their step. */ final GeneralSynchronizer experimentSemaphore = GeneralSynchronizer.withInitialPermits(0); - + /** The concurrency level (number of simulations that can run concurrently). */ final int concurrency; @@ -122,7 +122,7 @@ public class SimulationRunner implements ISimulationRunner { /** * Creates a SimulationRunner configured for the given simulation population. - * + * *

    * The concurrency level is determined based on: *

    @@ -130,7 +130,7 @@ public class SimulationRunner implements ISimulationRunner { *
  • For headless non-batch experiments: concurrency = 1 (sequential)
  • *
  • Otherwise: determined by experiment's concurrency expression and preferences
  • * - * + * * @param pop * the simulation population whose simulations will be managed * @return a new SimulationRunner configured appropriately for the experiment type @@ -148,7 +148,7 @@ public static SimulationRunner of(final IPopulation pop) { /** * Constructs a new SimulationRunner with the specified concurrency level. - * + * * @param concurrency * the maximum number of simulations that can execute concurrently (typically 1 for sequential or number * of CPU cores for parallel) @@ -211,18 +211,21 @@ private void runFreely(final Autonomy a) { while (!over && !shutdown && runnables.get(agent) == this) { try { while (runnables.get(agent) == this && a.isPaused.getAsBoolean() && !a.isOver.test(agent) - && !shutdown) { THREADS.WAIT(10); } + && !shutdown) { + THREADS.WAIT(10); + } if (runnables.get(agent) == this && !a.isOver.test(agent) && !shutdown) { agent.step(); } } catch (Throwable tg) { EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); } -try { - over = agent.dead() || a.isOver.test(agent); - } catch (final Throwable tg) { - EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); - over = true; + try { + over = agent.dead() || a.isOver.test(agent); + } catch (final Throwable tg) { + EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); + over = true; + } + if (!shutdown && runnables.get(agent) == this) { a.onOver.accept(agent); } } - if (!shutdown && runnables.get(agent) == this) { a.onOver.accept(agent); } } @Override @@ -236,10 +239,9 @@ public void run() { runFreely(autonomy); return; } - if (!acquired) { break; } // Recheck after waking up: dispose() may have released the permit just to // unblock this thread for shutdown — we must not step a dead/cleared runner. - if (shutdown || agent.dead()) { break; } + if (!acquired || shutdown || agent.dead()) { break; } try { agent.step(); } catch (Throwable tg) { @@ -269,9 +271,9 @@ public void runAutonomously(final ISimulationAgent agent, final Predicate * *

    - * This provides the synchronization needed for coordinated multi-simulation execution where all simulations - * advance together through simulation time. + * This provides the synchronization needed for coordinated multi-simulation execution where all simulations advance + * together through simulation time. *

    */ @Override @@ -334,7 +336,7 @@ public void dispose() { /** * Returns the set of simulation agents currently managed by this runner. - * + * * @return the set of active simulation agents */ @Override From 0269158862b7cfec27c211afd0229a07956a42f6 Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sat, 10 Oct 2026 12:38:49 +0700 Subject: [PATCH 06/12] Moves some models around --- .../models}/Batch Simulation/.project | 0 .../models}/Batch Simulation/Calibration.gaml | 0 .../models}/Batch Simulation/Exploration.gaml | 0 .../Batch Simulation/Results/exploration.csv | 31 ++++++++++++++++++ .../Batch Simulation/Results/preypredator.csv | 26 +++++++++++++++ .../includes/ParameterSets.csv | 0 .../models/Batch Simulation/results.csv | 19 +++++++++++ .../models}/Model Exploration/.project | 0 .../org.eclipse.core.resources.prefs | 0 .../.project | 2 +- .../org.eclipse.core.resources.prefs | 0 ... - Class Definition and Instantiation.gaml | 0 ...Classes - 02 - Attributes and Actions.gaml | 0 .../Classes - 03 - Inheritance.gaml | 0 .../Classes - 04 - Virtual Classes.gaml | 0 .../Classes - 05 - Advanced Features.gaml | 0 .../Classes and Objects Showcase.gaml | 0 .../recipes/Define Experiments/.project | 19 +++++++++++ .../org.eclipse.core.resources.prefs | 0 .../Experiment and simulation.gaml | 0 .../.project | 2 +- .../Multi-simulation.gaml | 0 .../.project | 2 +- .../org.eclipse.core.resources.prefs | 2 ++ .../Attribute access.gaml | 0 .../Inheritance.gaml | 0 ...pecies - creation and death of agents.gaml | 0 .../Mirror species.gaml | 0 .../includes/buildings_simple.dbf | Bin .../includes/buildings_simple.prj | 0 .../includes/buildings_simple.shp | Bin .../includes/buildings_simple.shx | Bin 32 files changed, 100 insertions(+), 3 deletions(-) rename {gama.library/recipes/Model Exploration => gama.extension.batch/models}/Batch Simulation/.project (100%) rename {gama.library/recipes/Model Exploration => gama.extension.batch/models}/Batch Simulation/Calibration.gaml (100%) rename {gama.library/recipes/Model Exploration => gama.extension.batch/models}/Batch Simulation/Exploration.gaml (100%) create mode 100644 gama.extension.batch/models/Batch Simulation/Results/exploration.csv create mode 100644 gama.extension.batch/models/Batch Simulation/Results/preypredator.csv rename {gama.library/recipes/Model Exploration => gama.extension.batch/models}/Batch Simulation/includes/ParameterSets.csv (100%) create mode 100644 gama.extension.batch/models/Batch Simulation/results.csv rename {gama.library/recipes => gama.extension.batch/models}/Model Exploration/.project (100%) rename {gama.library/recipes/Class Definition => gama.extension.batch/models/Model Exploration}/.settings/org.eclipse.core.resources.prefs (100%) rename gama.library/recipes/{Class Definition => Define Classes}/.project (93%) rename gama.library/recipes/{Model Exploration => Define Classes}/.settings/org.eclipse.core.resources.prefs (100%) rename gama.library/recipes/{Class Definition => Define Classes}/Classes - 01 - Class Definition and Instantiation.gaml (100%) rename gama.library/recipes/{Class Definition => Define Classes}/Classes - 02 - Attributes and Actions.gaml (100%) rename gama.library/recipes/{Class Definition => Define Classes}/Classes - 03 - Inheritance.gaml (100%) rename gama.library/recipes/{Class Definition => Define Classes}/Classes - 04 - Virtual Classes.gaml (100%) rename gama.library/recipes/{Class Definition => Define Classes}/Classes - 05 - Advanced Features.gaml (100%) rename gama.library/recipes/{Class Definition => Define Classes}/Classes and Objects Showcase.gaml (100%) create mode 100644 gama.library/recipes/Define Experiments/.project rename gama.library/recipes/{Species Definition => Define Experiments}/.settings/org.eclipse.core.resources.prefs (100%) rename gama.library/recipes/{Model Exploration/Experiment species => Define Experiments}/Experiment and simulation.gaml (100%) rename gama.library/recipes/{Model Exploration/Multi-simulation => Define Multiple Simulations}/.project (87%) rename gama.library/recipes/{Model Exploration/Multi-simulation => Define Multiple Simulations}/Multi-simulation.gaml (100%) rename gama.library/recipes/{Species Definition => Define Species}/.project (89%) create mode 100644 gama.library/recipes/Define Species/.settings/org.eclipse.core.resources.prefs rename gama.library/recipes/{Species Definition => Define Species}/Attribute access.gaml (100%) rename gama.library/recipes/{Species Definition => Define Species}/Inheritance.gaml (100%) rename gama.library/recipes/{Species Definition => Define Species}/Mirror species - creation and death of agents.gaml (100%) rename gama.library/recipes/{Species Definition => Define Species}/Mirror species.gaml (100%) rename gama.library/recipes/{Species Definition => Define Species}/includes/buildings_simple.dbf (100%) rename gama.library/recipes/{Species Definition => Define Species}/includes/buildings_simple.prj (100%) rename gama.library/recipes/{Species Definition => Define Species}/includes/buildings_simple.shp (100%) rename gama.library/recipes/{Species Definition => Define Species}/includes/buildings_simple.shx (100%) diff --git a/gama.library/recipes/Model Exploration/Batch Simulation/.project b/gama.extension.batch/models/Batch Simulation/.project similarity index 100% rename from gama.library/recipes/Model Exploration/Batch Simulation/.project rename to gama.extension.batch/models/Batch Simulation/.project diff --git a/gama.library/recipes/Model Exploration/Batch Simulation/Calibration.gaml b/gama.extension.batch/models/Batch Simulation/Calibration.gaml similarity index 100% rename from gama.library/recipes/Model Exploration/Batch Simulation/Calibration.gaml rename to gama.extension.batch/models/Batch Simulation/Calibration.gaml diff --git a/gama.library/recipes/Model Exploration/Batch Simulation/Exploration.gaml b/gama.extension.batch/models/Batch Simulation/Exploration.gaml similarity index 100% rename from gama.library/recipes/Model Exploration/Batch Simulation/Exploration.gaml rename to gama.extension.batch/models/Batch Simulation/Exploration.gaml diff --git a/gama.extension.batch/models/Batch Simulation/Results/exploration.csv b/gama.extension.batch/models/Batch Simulation/Results/exploration.csv new file mode 100644 index 0000000000..313deeb152 --- /dev/null +++ b/gama.extension.batch/models/Batch Simulation/Results/exploration.csv @@ -0,0 +1,31 @@ +prey_max_transfer,prey_energy_reproduce,predator_energy_transfer,predator_energy_reproduce,nb_preys,nb_predators,time +0.3829552836740046,0.6155660444737817,0.5771142786311795,0.5439461617119986,3,0,181.0 +0.3829552836740046,0.6155660444737817,0.5771142786311795,0.5439461617119986,21,0,224.0 +0.3829552836740046,0.6155660444737817,0.5771142786311795,0.5439461617119986,3,0,247.0 +0.47797887506927056,0.08555954031288505,0.7774029323599276,0.23868310957115263,1,0,122.0 +0.47797887506927056,0.08555954031288505,0.7774029323599276,0.23868310957115263,19,0,132.0 +0.47797887506927056,0.08555954031288505,0.7774029323599276,0.23868310957115263,88,17,501.0 +0.34330881432750465,0.10147626416873289,0.6125616373642396,0.4840228627530946,79,16,501.0 +0.34330881432750465,0.10147626416873289,0.6125616373642396,0.4840228627530946,77,13,501.0 +0.34330881432750465,0.10147626416873289,0.6125616373642396,0.4840228627530946,154,3,501.0 +0.26763879791591855,0.12540836684339102,0.4457315865171779,0.587623718536298,37,0,133.0 +0.26763879791591855,0.12540836684339102,0.4457315865171779,0.587623718536298,20,10,501.0 +0.26763879791591855,0.12540836684339102,0.4457315865171779,0.587623718536298,59,7,501.0 +0.38500912811399424,0.7170563395173344,0.9346652850043696,0.9477721270649239,23,0,183.0 +0.38500912811399424,0.7170563395173344,0.9346652850043696,0.9477721270649239,62,9,501.0 +0.38500912811399424,0.7170563395173344,0.9346652850043696,0.9477721270649239,69,9,501.0 +0.3859723419446254,0.4130643333041754,0.5866267099934919,0.30031186080660355,10,0,136.0 +0.3859723419446254,0.4130643333041754,0.5866267099934919,0.30031186080660355,63,4,501.0 +0.3859723419446254,0.4130643333041754,0.5866267099934919,0.30031186080660355,84,10,501.0 +0.4113867622966763,0.36682782626316485,0.9778677422918179,0.7601735734215916,0,10,89.0 +0.4113867622966763,0.36682782626316485,0.9778677422918179,0.7601735734215916,0,21,101.0 +0.4113867622966763,0.36682782626316485,0.9778677422918179,0.7601735734215916,0,21,108.0 +0.11906139365958134,0.4697449116948781,0.15770766476920034,0.5242876596264772,33,0,136.0 +0.11906139365958134,0.4697449116948781,0.15770766476920034,0.5242876596264772,23,0,192.0 +0.11906139365958134,0.4697449116948781,0.15770766476920034,0.5242876596264772,12,0,211.0 +0.2289220055842472,0.25678930642498177,0.6164808478019536,0.6824663700021785,0,29,70.0 +0.2289220055842472,0.25678930642498177,0.6164808478019536,0.6824663700021785,0,7,112.0 +0.2289220055842472,0.25678930642498177,0.6164808478019536,0.6824663700021785,38,0,214.0 +0.42339219328860683,0.578282140901726,0.1493629995882695,0.7712213534201516,20,0,120.0 +0.42339219328860683,0.578282140901726,0.1493629995882695,0.7712213534201516,18,0,144.0 +0.42339219328860683,0.578282140901726,0.1493629995882695,0.7712213534201516,46,8,501.0 \ No newline at end of file diff --git a/gama.extension.batch/models/Batch Simulation/Results/preypredator.csv b/gama.extension.batch/models/Batch Simulation/Results/preypredator.csv new file mode 100644 index 0000000000..f2d4bac071 --- /dev/null +++ b/gama.extension.batch/models/Batch Simulation/Results/preypredator.csv @@ -0,0 +1,26 @@ +nb_preys,nb_predators +23,0 +38,0 +21,0 +23,0 +29,0 +26,0 +17,0 +3,0 +28,0 +7,0 +53,0 +22,0 +23,0 +13,0 +1,0 +21,0 +2,0 +19,0 +42,0 +1,0 +26,0 +41,0 +8,0 +79,0 +24,0 diff --git a/gama.library/recipes/Model Exploration/Batch Simulation/includes/ParameterSets.csv b/gama.extension.batch/models/Batch Simulation/includes/ParameterSets.csv similarity index 100% rename from gama.library/recipes/Model Exploration/Batch Simulation/includes/ParameterSets.csv rename to gama.extension.batch/models/Batch Simulation/includes/ParameterSets.csv diff --git a/gama.extension.batch/models/Batch Simulation/results.csv b/gama.extension.batch/models/Batch Simulation/results.csv new file mode 100644 index 0000000000..81d5458c4f --- /dev/null +++ b/gama.extension.batch/models/Batch Simulation/results.csv @@ -0,0 +1,19 @@ +int(self),prey_max_transfer,prey_energy_reproduce,predator_energy_transfer,predator_energy_reproduce,self.nb_predators,self.nb_preys +0,0.25,0.15,0.3,0.5,5,76 +1,0.25,0.15,0.3,0.5,0,128 +2,0.2,0.15,0.3,0.5,1,14 +3,0.2,0.15,0.3,0.5,0,58 +4,0.3,0.15,0.3,0.5,0,0 +5,0.3,0.15,0.3,0.5,4,144 +6,0.25,0.1,0.3,0.5,0,22 +7,0.25,0.1,0.3,0.5,1,59 +8,0.25,0.2,0.3,0.5,1,83 +9,0.25,0.2,0.3,0.5,3,204 +10,0.25,0.15,0.2,0.5,0,10 +11,0.25,0.15,0.2,0.5,0,74 +12,0.25,0.15,0.4,0.5,0,40 +13,0.25,0.15,0.4,0.5,0,0 +14,0.25,0.15,0.3,0.4,2,127 +15,0.25,0.15,0.3,0.4,0,66 +16,0.25,0.15,0.3,0.6,0,116 +17,0.25,0.15,0.3,0.6,4,16 diff --git a/gama.library/recipes/Model Exploration/.project b/gama.extension.batch/models/Model Exploration/.project similarity index 100% rename from gama.library/recipes/Model Exploration/.project rename to gama.extension.batch/models/Model Exploration/.project diff --git a/gama.library/recipes/Class Definition/.settings/org.eclipse.core.resources.prefs b/gama.extension.batch/models/Model Exploration/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from gama.library/recipes/Class Definition/.settings/org.eclipse.core.resources.prefs rename to gama.extension.batch/models/Model Exploration/.settings/org.eclipse.core.resources.prefs diff --git a/gama.library/recipes/Class Definition/.project b/gama.library/recipes/Define Classes/.project similarity index 93% rename from gama.library/recipes/Class Definition/.project rename to gama.library/recipes/Define Classes/.project index 1c115832d2..8dba6de6cb 100644 --- a/gama.library/recipes/Class Definition/.project +++ b/gama.library/recipes/Define Classes/.project @@ -1,6 +1,6 @@ - Class Definition + Define Classes diff --git a/gama.library/recipes/Model Exploration/.settings/org.eclipse.core.resources.prefs b/gama.library/recipes/Define Classes/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from gama.library/recipes/Model Exploration/.settings/org.eclipse.core.resources.prefs rename to gama.library/recipes/Define Classes/.settings/org.eclipse.core.resources.prefs diff --git a/gama.library/recipes/Class Definition/Classes - 01 - Class Definition and Instantiation.gaml b/gama.library/recipes/Define Classes/Classes - 01 - Class Definition and Instantiation.gaml similarity index 100% rename from gama.library/recipes/Class Definition/Classes - 01 - Class Definition and Instantiation.gaml rename to gama.library/recipes/Define Classes/Classes - 01 - Class Definition and Instantiation.gaml diff --git a/gama.library/recipes/Class Definition/Classes - 02 - Attributes and Actions.gaml b/gama.library/recipes/Define Classes/Classes - 02 - Attributes and Actions.gaml similarity index 100% rename from gama.library/recipes/Class Definition/Classes - 02 - Attributes and Actions.gaml rename to gama.library/recipes/Define Classes/Classes - 02 - Attributes and Actions.gaml diff --git a/gama.library/recipes/Class Definition/Classes - 03 - Inheritance.gaml b/gama.library/recipes/Define Classes/Classes - 03 - Inheritance.gaml similarity index 100% rename from gama.library/recipes/Class Definition/Classes - 03 - Inheritance.gaml rename to gama.library/recipes/Define Classes/Classes - 03 - Inheritance.gaml diff --git a/gama.library/recipes/Class Definition/Classes - 04 - Virtual Classes.gaml b/gama.library/recipes/Define Classes/Classes - 04 - Virtual Classes.gaml similarity index 100% rename from gama.library/recipes/Class Definition/Classes - 04 - Virtual Classes.gaml rename to gama.library/recipes/Define Classes/Classes - 04 - Virtual Classes.gaml diff --git a/gama.library/recipes/Class Definition/Classes - 05 - Advanced Features.gaml b/gama.library/recipes/Define Classes/Classes - 05 - Advanced Features.gaml similarity index 100% rename from gama.library/recipes/Class Definition/Classes - 05 - Advanced Features.gaml rename to gama.library/recipes/Define Classes/Classes - 05 - Advanced Features.gaml diff --git a/gama.library/recipes/Class Definition/Classes and Objects Showcase.gaml b/gama.library/recipes/Define Classes/Classes and Objects Showcase.gaml similarity index 100% rename from gama.library/recipes/Class Definition/Classes and Objects Showcase.gaml rename to gama.library/recipes/Define Classes/Classes and Objects Showcase.gaml diff --git a/gama.library/recipes/Define Experiments/.project b/gama.library/recipes/Define Experiments/.project new file mode 100644 index 0000000000..46ccc470ac --- /dev/null +++ b/gama.library/recipes/Define Experiments/.project @@ -0,0 +1,19 @@ + + + Define Experiments + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.eclipse.xtext.ui.shared.xtextNature + gama.workspace.gamaNature + gama.workspace.recipeNature + + diff --git a/gama.library/recipes/Species Definition/.settings/org.eclipse.core.resources.prefs b/gama.library/recipes/Define Experiments/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from gama.library/recipes/Species Definition/.settings/org.eclipse.core.resources.prefs rename to gama.library/recipes/Define Experiments/.settings/org.eclipse.core.resources.prefs diff --git a/gama.library/recipes/Model Exploration/Experiment species/Experiment and simulation.gaml b/gama.library/recipes/Define Experiments/Experiment and simulation.gaml similarity index 100% rename from gama.library/recipes/Model Exploration/Experiment species/Experiment and simulation.gaml rename to gama.library/recipes/Define Experiments/Experiment and simulation.gaml diff --git a/gama.library/recipes/Model Exploration/Multi-simulation/.project b/gama.library/recipes/Define Multiple Simulations/.project similarity index 87% rename from gama.library/recipes/Model Exploration/Multi-simulation/.project rename to gama.library/recipes/Define Multiple Simulations/.project index 6669021fa2..b726ec29ba 100644 --- a/gama.library/recipes/Model Exploration/Multi-simulation/.project +++ b/gama.library/recipes/Define Multiple Simulations/.project @@ -1,6 +1,6 @@ - Multi-simulation + Define Multiple Simulations diff --git a/gama.library/recipes/Model Exploration/Multi-simulation/Multi-simulation.gaml b/gama.library/recipes/Define Multiple Simulations/Multi-simulation.gaml similarity index 100% rename from gama.library/recipes/Model Exploration/Multi-simulation/Multi-simulation.gaml rename to gama.library/recipes/Define Multiple Simulations/Multi-simulation.gaml diff --git a/gama.library/recipes/Species Definition/.project b/gama.library/recipes/Define Species/.project similarity index 89% rename from gama.library/recipes/Species Definition/.project rename to gama.library/recipes/Define Species/.project index af4036958d..dab919d42f 100644 --- a/gama.library/recipes/Species Definition/.project +++ b/gama.library/recipes/Define Species/.project @@ -1,6 +1,6 @@ - Species Definition + Define Species diff --git a/gama.library/recipes/Define Species/.settings/org.eclipse.core.resources.prefs b/gama.library/recipes/Define Species/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..99f26c0203 --- /dev/null +++ b/gama.library/recipes/Define Species/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/gama.library/recipes/Species Definition/Attribute access.gaml b/gama.library/recipes/Define Species/Attribute access.gaml similarity index 100% rename from gama.library/recipes/Species Definition/Attribute access.gaml rename to gama.library/recipes/Define Species/Attribute access.gaml diff --git a/gama.library/recipes/Species Definition/Inheritance.gaml b/gama.library/recipes/Define Species/Inheritance.gaml similarity index 100% rename from gama.library/recipes/Species Definition/Inheritance.gaml rename to gama.library/recipes/Define Species/Inheritance.gaml diff --git a/gama.library/recipes/Species Definition/Mirror species - creation and death of agents.gaml b/gama.library/recipes/Define Species/Mirror species - creation and death of agents.gaml similarity index 100% rename from gama.library/recipes/Species Definition/Mirror species - creation and death of agents.gaml rename to gama.library/recipes/Define Species/Mirror species - creation and death of agents.gaml diff --git a/gama.library/recipes/Species Definition/Mirror species.gaml b/gama.library/recipes/Define Species/Mirror species.gaml similarity index 100% rename from gama.library/recipes/Species Definition/Mirror species.gaml rename to gama.library/recipes/Define Species/Mirror species.gaml diff --git a/gama.library/recipes/Species Definition/includes/buildings_simple.dbf b/gama.library/recipes/Define Species/includes/buildings_simple.dbf similarity index 100% rename from gama.library/recipes/Species Definition/includes/buildings_simple.dbf rename to gama.library/recipes/Define Species/includes/buildings_simple.dbf diff --git a/gama.library/recipes/Species Definition/includes/buildings_simple.prj b/gama.library/recipes/Define Species/includes/buildings_simple.prj similarity index 100% rename from gama.library/recipes/Species Definition/includes/buildings_simple.prj rename to gama.library/recipes/Define Species/includes/buildings_simple.prj diff --git a/gama.library/recipes/Species Definition/includes/buildings_simple.shp b/gama.library/recipes/Define Species/includes/buildings_simple.shp similarity index 100% rename from gama.library/recipes/Species Definition/includes/buildings_simple.shp rename to gama.library/recipes/Define Species/includes/buildings_simple.shp diff --git a/gama.library/recipes/Species Definition/includes/buildings_simple.shx b/gama.library/recipes/Define Species/includes/buildings_simple.shx similarity index 100% rename from gama.library/recipes/Species Definition/includes/buildings_simple.shx rename to gama.library/recipes/Define Species/includes/buildings_simple.shx From f2b4adac0e092c514c8f4a79c61856d099b99dab Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sat, 10 Oct 2026 14:35:12 +0700 Subject: [PATCH 07/12] Remove useless folder --- .../models/Model Exploration/.project | 19 ------------------- .../org.eclipse.core.resources.prefs | 2 -- 2 files changed, 21 deletions(-) delete mode 100644 gama.extension.batch/models/Model Exploration/.project delete mode 100644 gama.extension.batch/models/Model Exploration/.settings/org.eclipse.core.resources.prefs diff --git a/gama.extension.batch/models/Model Exploration/.project b/gama.extension.batch/models/Model Exploration/.project deleted file mode 100644 index da2451cb7b..0000000000 --- a/gama.extension.batch/models/Model Exploration/.project +++ /dev/null @@ -1,19 +0,0 @@ - - - Model Exploration - - - - - - org.eclipse.xtext.ui.shared.xtextBuilder - - - - - - org.eclipse.xtext.ui.shared.xtextNature - gama.workspace.gamaNature - gama.workspace.recipeNature - - \ No newline at end of file diff --git a/gama.extension.batch/models/Model Exploration/.settings/org.eclipse.core.resources.prefs b/gama.extension.batch/models/Model Exploration/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 99f26c0203..0000000000 --- a/gama.extension.batch/models/Model Exploration/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 From db48719c84b0e325a49a4af8374f4c5946641cf6 Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sat, 10 Oct 2026 15:20:34 +0700 Subject: [PATCH 08/12] Correctly reports runtime errors when interrupting too soon --- .../api/exceptions/GamaRuntimeException.java | 121 ++++++++++-------- .../DefaultExperimentController.java | 27 ++-- .../models/Batch Simulation/.project | 5 +- .../models/Batch Simulation/Exploration.gaml | 7 +- .../exploration/AExplorationAlgorithm.java | 12 +- .../Define Multiple Simulations/.project | 3 +- 6 files changed, 100 insertions(+), 75 deletions(-) diff --git a/gama.api/src/gama/api/exceptions/GamaRuntimeException.java b/gama.api/src/gama/api/exceptions/GamaRuntimeException.java index 5cf1c142c7..643f85a737 100644 --- a/gama.api/src/gama/api/exceptions/GamaRuntimeException.java +++ b/gama.api/src/gama/api/exceptions/GamaRuntimeException.java @@ -25,8 +25,8 @@ /** * Base exception class for all runtime exceptions in GAMA. *

    - * This exception is thrown when an abnormal situation occurs during model execution. It provides - * comprehensive context information including: + * This exception is thrown when an abnormal situation occurs during model execution. It provides comprehensive context + * information including: *

    *
      *
    • The simulation cycle at which the error occurred
    • @@ -36,11 +36,10 @@ *
    • Stack trace and contextual information for debugging
    • *
    *

    - * GamaRuntimeException can be configured to track multiple occurrences of the same error across - * different agents, providing aggregated error reporting to avoid flooding the user with duplicate - * messages. + * GamaRuntimeException can be configured to track multiple occurrences of the same error across different agents, + * providing aggregated error reporting to avoid flooding the user with duplicate messages. *

    - * + * * @author drogoul * @since 7 janv. 2011 */ @@ -75,12 +74,14 @@ public class GamaRuntimeException extends RuntimeException { /** * Creates a GamaRuntimeException from a generic Throwable. *

    - * This factory method wraps different types of exceptions into appropriate GAMA exception types, - * such as {@link GamaRuntimeFileException} for I/O errors. + * This factory method wraps different types of exceptions into appropriate GAMA exception types, such as + * {@link GamaRuntimeFileException} for I/O errors. *

    * - * @param ex the throwable to wrap - * @param scope the execution scope in which the exception occurred + * @param ex + * the throwable to wrap + * @param scope + * the execution scope in which the exception occurred * @return a GamaRuntimeException wrapping the throwable */ public static GamaRuntimeException create(final Throwable ex, final IScope scope) { @@ -94,8 +95,10 @@ public static GamaRuntimeException create(final Throwable ex, final IScope scope /** * Creates a GamaRuntimeException representing an error. * - * @param s the error message - * @param scope the execution scope + * @param s + * the error message + * @param scope + * the execution scope * @return a new error exception */ public static GamaRuntimeException error(final String s, final IScope scope) { @@ -105,8 +108,10 @@ public static GamaRuntimeException error(final String s, final IScope scope) { /** * Creates a GamaRuntimeException representing a warning. * - * @param s the warning message - * @param scope the execution scope + * @param s + * the warning message + * @param scope + * the execution scope * @return a new warning exception */ public static GamaRuntimeException warning(final String s, final IScope scope) { @@ -118,11 +123,12 @@ public static GamaRuntimeException warning(final String s, final IScope scope) { /** * Extracts a user-friendly exception name from a Throwable. *

    - * This method provides specialized names for common exception types and library-specific - * exceptions to improve error message clarity for users. + * This method provides specialized names for common exception types and library-specific exceptions to improve + * error message clarity for users. *

    * - * @param ex the exception + * @param ex + * the exception * @return a user-friendly name for the exception */ @SuppressWarnings ("unused") @@ -149,13 +155,14 @@ protected static String getExceptionName(final Throwable ex) { /** * Constructs a GamaRuntimeException from a Throwable. *

    - * This constructor wraps a Java exception and captures the current execution context - * including the symbol being executed and the simulation cycle. It also includes - * stack trace information from the original exception. + * This constructor wraps a Java exception and captures the current execution context including the symbol being + * executed and the simulation cycle. It also includes stack trace information from the original exception. *

    * - * @param scope the execution scope - * @param ex the underlying exception + * @param scope + * the execution scope + * @param ex + * the underlying exception */ protected GamaRuntimeException(final IScope scope, final Throwable ex) { super(ex == null ? "Error" : "Java error: " + getExceptionName(ex), ex); @@ -181,13 +188,16 @@ protected GamaRuntimeException(final IScope scope, final Throwable ex) { /** * Constructs a GamaRuntimeException with a custom message. *

    - * This constructor creates an exception with a user-specified message and allows - * configuring whether it represents a warning or error. + * This constructor creates an exception with a user-specified message and allows configuring whether it represents + * a warning or error. *

    * - * @param scope the execution scope - * @param s the exception message - * @param warning true if this is a warning, false if it's an error + * @param scope + * the execution scope + * @param s + * the exception message + * @param warning + * true if this is a warning, false if it's an error */ protected GamaRuntimeException(final IScope scope, final String s, final boolean warning) { super(s); @@ -205,11 +215,12 @@ protected GamaRuntimeException(final IScope scope, final String s, final boolean /** * Adds a context string to this exception. *

    - * Context strings provide additional information about where and how the exception occurred, - * helping with debugging and error reporting. + * Context strings provide additional information about where and how the exception occurred, helping with debugging + * and error reporting. *

    * - * @param c the context string to add + * @param c + * the context string to add */ public void addContext(final String c) { context.add(c); @@ -218,12 +229,12 @@ public void addContext(final String c) { /** * Adds context information from a GAML symbol. *

    - * This method extracts contextual information from a symbol (such as its GAML representation) - * and adds it to the exception's context. It also captures the underlying model element - * for editor integration. + * This method extracts contextual information from a symbol (such as its GAML representation) and adds it to the + * exception's context. It also captures the underlying model element for editor integration. *

    * - * @param s the symbol to extract context from + * @param s + * the symbol to extract context from */ public void addContext(final ISymbol s) { String serial = s.serializeToGaml(false); @@ -242,11 +253,12 @@ public void addContext(final ISymbol s) { /** * Adds an agent name to the list of agents affected by this exception. *

    - * This method is used to track which agents encountered this exception. It prevents - * duplicate entries and increments the occurrence counter. + * This method is used to track which agents encountered this exception. It prevents duplicate entries and + * increments the occurrence counter. *

    * - * @param agent the name of the agent to add + * @param agent + * the name of the agent to add */ public void addAgent(final String agent) { occurrences++; @@ -257,7 +269,8 @@ public void addAgent(final String agent) { /** * Adds multiple agent names to the list of affected agents. * - * @param agents the list of agent names to add + * @param agents + * the list of agent names to add */ public void addAgents(final List agents) { for (final String agent : agents) { addAgent(agent); } @@ -273,8 +286,7 @@ public void addAgents(final List agents) { /** * Gets a summary string describing the agents affected by this exception. *

    - * The summary includes the number of occurrences and the affected agents, - * formatted for user-friendly display. + * The summary includes the number of occurrences and the affected agents, formatted for user-friendly display. *

    * * @return a formatted string summarizing affected agents @@ -297,7 +309,8 @@ public String getAgentSummary() { /** * Computes the current simulation cycle from a scope. * - * @param scope the execution scope + * @param scope + * the execution scope * @return the current cycle number, or 0 if not available */ public long computeCycle(final IScope scope) { @@ -308,8 +321,8 @@ public long computeCycle(final IScope scope) { /** * Gets the full context information as a list of strings. *

    - * This includes the simulation name, affected agents, and all context strings - * that have been added to this exception. + * This includes the simulation name, affected agents, and all context strings that have been added to this + * exception. *

    * * @return the context as a list of strings @@ -348,12 +361,12 @@ public String toString() { /** * Checks if this exception is equivalent to another exception. *

    - * Two exceptions are considered equivalent if they have the same message, editor context, - * simulation root, and occurred in the same cycle. This is used to avoid reporting - * duplicate exceptions. + * Two exceptions are considered equivalent if they have the same message, editor context, simulation root, and + * occurred in the same cycle. This is used to avoid reporting duplicate exceptions. *

    * - * @param ex the exception to compare with + * @param ex + * the exception to compare with * @return true if the exceptions are equivalent */ public boolean equivalentTo(final GamaRuntimeException ex) { @@ -385,9 +398,8 @@ public void setReported() { /** * Gets the complete exception message including all context information. *

    - * This method returns a formatted string containing the agent summary, cycle number, - * exception message, and all context information, suitable for display in error logs - * or user interfaces. + * This method returns a formatted string containing the agent summary, cycle number, exception message, and all + * context information, suitable for display in error logs or user interfaces. *

    * * @return the full exception text with context @@ -405,8 +417,8 @@ public String getAllText() { /** * Checks if this exception is invalid and should not be reported. *

    - * An exception is considered invalid if the simulation or experiment has been closed - * or is no longer valid. Invalid exceptions are typically not shown to the user. + * An exception is considered invalid if the simulation or experiment has been closed or is no longer valid. Invalid + * exceptions are typically not shown to the user. *

    * * @return true if the exception is invalid @@ -421,4 +433,9 @@ public String getAllText() { */ public ITopLevelAgent getTopLevelAgent() { return scope == null ? null : scope.getRoot(); } + /** + * @return + */ + public IScope getScope() { return scope; } + } diff --git a/gama.api/src/gama/api/kernel/simulation/DefaultExperimentController.java b/gama.api/src/gama/api/kernel/simulation/DefaultExperimentController.java index 9eece033e9..393c66ca3f 100644 --- a/gama.api/src/gama/api/kernel/simulation/DefaultExperimentController.java +++ b/gama.api/src/gama/api/kernel/simulation/DefaultExperimentController.java @@ -315,11 +315,10 @@ protected boolean processUserCommand(final ExperimentCommand command) { try { final boolean wasRunning = !isPaused() && !experiment.isAutorun(); paused = true; - currentScope.getGui().getStatus().waitStatus("Reloading...", IStatusMessage.SIMULATION_ICON, - () -> { - currentScope.getGui().showLaunchingOverlay(experiment.getName()); - experiment.reload(); - }); + currentScope.getGui().getStatus().waitStatus("Reloading...", IStatusMessage.SIMULATION_ICON, () -> { + currentScope.getGui().showLaunchingOverlay(experiment.getName()); + experiment.reload(); + }); if (wasRunning) return processUserCommand(_START_CMD); currentScope.getGui().getStatus().informStatus("Experiment reloaded", IStatusMessage.SIMULATION_ICON); @@ -438,7 +437,8 @@ public void close() { * the throwable that caused the failure */ public void notifyExceptionAndCloseExperiment(final Throwable e) { - final IScope localScope = scope; // capture before concurrent dispose() can null it + IScope localScope = scope; // capture before concurrent dispose() can null it + if (localScope == null && e instanceof GamaRuntimeException gre) { localScope = gre.getScope(); } if (e != null && localScope != null) { final GamaRuntimeException gre = GamaRuntimeException.create(e, localScope); // Report to the errors view BEFORE closing so that isDisposing() is still false @@ -455,8 +455,8 @@ public void notifyExceptionAndCloseExperiment(final Throwable e) { * *

    * This is used for initialisation-time errors (thrown from {@link #schedule}) where the simulation has not been - * fully created yet. The experiment perspective remains visible so the error stays accessible. Any subsequent - * model launch will close this failed experiment cleanly via {@link gama.api.GAMA#runGuiExperiment}. + * fully created yet. The experiment perspective remains visible so the error stays accessible. Any subsequent model + * launch will close this failed experiment cleanly via {@link gama.api.GAMA#runGuiExperiment}. *

    * *

    @@ -481,7 +481,8 @@ public void notifyExceptionAndCloseExperiment(final Throwable e) { * the throwable thrown during experiment initialisation */ protected void notifyExceptionAndReloadExperiment(final Throwable e) { - final IScope localScope = scope; + IScope localScope = scope; + if (localScope == null && e instanceof GamaRuntimeException gre) { localScope = gre.getScope(); } final GamaRuntimeException gre = e != null && localScope != null ? GamaRuntimeException.create(e, localScope) : null; @@ -591,11 +592,9 @@ protected void step() { // Block if paused - wait for START or STEP command to release lock. // If the execution thread is interrupted while waiting, return immediately // so it can exit the while(experimentAlive) loop cleanly. - if (paused) { - // dispose() sets experimentAlive = false BEFORE releasing the lock so that - // the execution thread can exit cleanly without executing one extra step. - if (!lock.acquire() || !experimentAlive) return; - } + // dispose() sets experimentAlive = false BEFORE releasing the lock so that + // the execution thread can exit cleanly without executing one extra step. + if (paused && (!lock.acquire() || !experimentAlive)) return; // Cache scope reference to avoid repeated volatile reads final IScope currentScope = scope; diff --git a/gama.extension.batch/models/Batch Simulation/.project b/gama.extension.batch/models/Batch Simulation/.project index 4e5d9a7d3d..7e282e8e2a 100644 --- a/gama.extension.batch/models/Batch Simulation/.project +++ b/gama.extension.batch/models/Batch Simulation/.project @@ -1,7 +1,7 @@ Batch Simulation - + batch plugin @@ -13,6 +13,7 @@ org.eclipse.xtext.ui.shared.xtextNature - msi.gama.application.gamaNature + gama.workspace.gamaNature + gama.workspace.pluginNature diff --git a/gama.extension.batch/models/Batch Simulation/Exploration.gaml b/gama.extension.batch/models/Batch Simulation/Exploration.gaml index c02c7c2cde..123415e288 100644 --- a/gama.extension.batch/models/Batch Simulation/Exploration.gaml +++ b/gama.extension.batch/models/Batch Simulation/Exploration.gaml @@ -13,7 +13,8 @@ model Exploration -import "../../Predator Prey/models/Model 13.gaml" +import "../Predator Prey/models/Model 13.gaml" + /* * Change a little bit the behavior of the world agent to fit exploration requirements @@ -91,9 +92,9 @@ experiment exhaustive_exploration parent: batch_abstract type: batch keep_seed: // repeating each simulation three times (the aggregated fitness correspond to the mean fitness), experiment explicit_exploration parent: batch_abstract type: batch repeat: 3 keep_seed: true until: world.stop_sim() or ( time > end_cycle ) { method exploration with: [ - [prey_max_transfer::0.1, predator_energy_transfer:: 0.01], + [prey_max_transfer::0.1, predator_energy_transfer:: 0.1], [prey_max_transfer::0.5, predator_energy_transfer:: 0.2], - [prey_max_transfer::1.0, predator_energy_transfer:: 0.05], + [prey_max_transfer::1.0, predator_energy_transfer:: 0.5], [prey_max_transfer::0.5, predator_energy_transfer:: 0.1] ]; } diff --git a/gama.extension.batch/src/gama/extension/batch/exploration/AExplorationAlgorithm.java b/gama.extension.batch/src/gama/extension/batch/exploration/AExplorationAlgorithm.java index 09021993f5..3cf4158bf8 100644 --- a/gama.extension.batch/src/gama/extension/batch/exploration/AExplorationAlgorithm.java +++ b/gama.extension.batch/src/gama/extension/batch/exploration/AExplorationAlgorithm.java @@ -418,13 +418,19 @@ private List buildParameterFromMap(final IScope scope) { * the parameter sets * @return the list */ + @SuppressWarnings ("unchecked") private List buildParametersSetList(final IScope scope, final List> parameterSets) { var sets = new ArrayList(); - for (Map parameterSet : parameterSets) { + for (Map parameterSet : (List>) (List) parameterSets) { ParametersSet p = new ParametersSet(); - for (Entry entry : parameterSet.entrySet()) { - p.put(entry.getKey(), entry.getValue() instanceof IExpression + for (Entry entry : parameterSet.entrySet()) { + if (!(entry.getKey() instanceof String)) { + GAMA.reportAndThrowIfNeeded(scope, GamaRuntimeException.error("Parameter names in the '" + + IKeyword.WITH + "' facet must be strings (e.g. \"my_param\"::0.5), got: " + + entry.getKey(), scope), true); + } + p.put((String) entry.getKey(), entry.getValue() instanceof IExpression ? ((IExpression) entry.getValue()).value(scope) : entry.getValue()); } sets.add(p); diff --git a/gama.library/recipes/Define Multiple Simulations/.project b/gama.library/recipes/Define Multiple Simulations/.project index b726ec29ba..ec91c5e763 100644 --- a/gama.library/recipes/Define Multiple Simulations/.project +++ b/gama.library/recipes/Define Multiple Simulations/.project @@ -13,6 +13,7 @@ org.eclipse.xtext.ui.shared.xtextNature - msi.gama.application.gamaNature + gama.workspace.gamaNature + gama.workspace.builtinNature From d142ceefbf5c71d04fd6e4706316e08c05724118 Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sat, 10 Oct 2026 16:00:42 +0700 Subject: [PATCH 09/12] Fixes the problem with explicit explorations --- .../gama/api/runtime/SimulationRunner.java | 23 +++++++++++++++---- .../models/Batch Simulation/Exploration.gaml | 8 +++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/gama.api/src/gama/api/runtime/SimulationRunner.java b/gama.api/src/gama/api/runtime/SimulationRunner.java index 52b8118a58..a951257bec 100644 --- a/gama.api/src/gama/api/runtime/SimulationRunner.java +++ b/gama.api/src/gama/api/runtime/SimulationRunner.java @@ -21,6 +21,8 @@ import java.util.function.Consumer; import java.util.function.Predicate; +import gama.api.GAMA; +import gama.api.exceptions.GamaRuntimeException; import gama.api.kernel.agent.IPopulation; import gama.api.kernel.simulation.ISimulationAgent; import gama.api.kernel.species.IExperimentSpecies; @@ -205,9 +207,20 @@ private final class SimulationThread extends Thread { setDaemon(true); } + /** Shows the error to the user (and not only in the console) */ + private void report(final Throwable tg) { + try { + final var scope = agent.getScope(); + GAMA.reportError(scope, tg instanceof GamaRuntimeException g ? g : GamaRuntimeException.create(tg, scope), + false); + } catch (final Throwable ignored) { + EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); + } + } + /** Steps the simulation as fast as possible until it is over. */ private void runFreely(final Autonomy a) { - boolean over = false; + boolean over = false, failed = false; while (!over && !shutdown && runnables.get(agent) == this) { try { while (runnables.get(agent) == this && a.isPaused.getAsBoolean() && !a.isOver.test(agent) @@ -216,15 +229,17 @@ private void runFreely(final Autonomy a) { } if (runnables.get(agent) == this && !a.isOver.test(agent) && !shutdown) { agent.step(); } } catch (Throwable tg) { - EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); + // A simulation that fails would otherwise fail again at every step, forever + report(tg); + failed = true; } try { - over = agent.dead() || a.isOver.test(agent); + over = failed || agent.dead() || a.isOver.test(agent); } catch (final Throwable tg) { EXCEPTION_HANDLER.uncaughtException(Thread.currentThread(), tg); over = true; } - if (!shutdown && runnables.get(agent) == this) { a.onOver.accept(agent); } + if (over && !shutdown && runnables.get(agent) == this) { a.onOver.accept(agent); } } } diff --git a/gama.extension.batch/models/Batch Simulation/Exploration.gaml b/gama.extension.batch/models/Batch Simulation/Exploration.gaml index 123415e288..d44af2e492 100644 --- a/gama.extension.batch/models/Batch Simulation/Exploration.gaml +++ b/gama.extension.batch/models/Batch Simulation/Exploration.gaml @@ -92,10 +92,10 @@ experiment exhaustive_exploration parent: batch_abstract type: batch keep_seed: // repeating each simulation three times (the aggregated fitness correspond to the mean fitness), experiment explicit_exploration parent: batch_abstract type: batch repeat: 3 keep_seed: true until: world.stop_sim() or ( time > end_cycle ) { method exploration with: [ - [prey_max_transfer::0.1, predator_energy_transfer:: 0.1], - [prey_max_transfer::0.5, predator_energy_transfer:: 0.2], - [prey_max_transfer::1.0, predator_energy_transfer:: 0.5], - [prey_max_transfer::0.5, predator_energy_transfer:: 0.1] + ["prey_max_transfer"::0.1, "predator_energy_transfer":: 0.1], + ["prey_max_transfer"::0.5, "predator_energy_transfer":: 0.2], + ["prey_max_transfer"::1.0, "predator_energy_transfer":: 0.5], + ["prey_max_transfer"::0.5, "predator_energy_transfer":: 0.1] ]; } From 6d919752873645a1f595556b399ba5602effad94 Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sat, 10 Oct 2026 18:19:31 +0700 Subject: [PATCH 10/12] Fixes some issues in batch tests models --- gama.extension.batch/build.properties | 3 +- .../models/Batch Tests/.project | 19 +++++ .../models/Batch Tests/Batch Regression.gaml | 71 +++++++++++++++++++ .../Batch Tests}/BatchAdvancedTest.experiment | 0 .../Batch Tests}/Exploration Facets Test.gaml | 19 +---- .../models/Batch Tests/README.md | 21 ++++++ gama.extension.batch/plugin.xml | 15 ++-- 7 files changed, 121 insertions(+), 27 deletions(-) create mode 100644 gama.extension.batch/models/Batch Tests/.project create mode 100644 gama.extension.batch/models/Batch Tests/Batch Regression.gaml rename gama.extension.batch/{tests/models => models/Batch Tests}/BatchAdvancedTest.experiment (100%) rename gama.extension.batch/{tests/Exploration Tests/models => models/Batch Tests}/Exploration Facets Test.gaml (83%) create mode 100644 gama.extension.batch/models/Batch Tests/README.md diff --git a/gama.extension.batch/build.properties b/gama.extension.batch/build.properties index 2d05a8298d..4b9943d218 100644 --- a/gama.extension.batch/build.properties +++ b/gama.extension.batch/build.properties @@ -5,5 +5,6 @@ jre.compilation.profile = JavaSE-25 bin.includes = META-INF/,\ .,\ plugin.xml,\ - tests/ + tests/,\ + models/ javacDefaultEncoding.. = UTF-8 diff --git a/gama.extension.batch/models/Batch Tests/.project b/gama.extension.batch/models/Batch Tests/.project new file mode 100644 index 0000000000..3dd930b215 --- /dev/null +++ b/gama.extension.batch/models/Batch Tests/.project @@ -0,0 +1,19 @@ + + + Batch Tests + batch plugin + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.eclipse.xtext.ui.shared.xtextNature + gama.workspace.gamaNature + gama.workspace.pluginNature + + diff --git a/gama.extension.batch/models/Batch Tests/Batch Regression.gaml b/gama.extension.batch/models/Batch Tests/Batch Regression.gaml new file mode 100644 index 0000000000..66a442404e --- /dev/null +++ b/gama.extension.batch/models/Batch Tests/Batch Regression.gaml @@ -0,0 +1,71 @@ +/** +* Name: Batch Regression +* Description: Manually-run regression models for batch experiments (PR #1252: autonomous simulations, per-simulation +* 'until', explicit 'with:' plans). Run each experiment and check the console: every check writes "PASS" or "FAIL". +* See README.md in this folder for what cannot be checked from GAML (threads, status bar, reload). +*/ + +model batch_regression + +global { + // Each simulation has its own random target: if simulations were stepped in lock-step, or stopped by another + // simulation's condition, some would not end exactly on their own target. + int target <- rnd(5, 40); + float p <- 0.0; + bool is_over -> cycle >= target; + bool stop_sim() { return is_over; } +} + +// Writes the result of the checks on the simulations of one run (called at the end of each run). +experiment regression_abstract type: batch virtual: true until: world.stop_sim() { + parameter "p" var: p min: 0.0 max: 1.0 step: 0.5; + + action check(string title) { + bool until_ok <- simulations all_match (each.cycle = each.target); + write title + " | each simulation stops at its own target: " + (until_ok ? "PASS" : "FAIL"); + } +} + +// 1. Each simulation must stop on its own 'until' condition, whatever the concurrency. +experiment until_sequential parent: regression_abstract type: batch repeat: 6 parallel: 1 keep_seed: true + until: world.stop_sim() { + method exploration; + reflex end_of_runs { do check("until_sequential"); } +} + +experiment until_parallel parent: regression_abstract type: batch repeat: 6 parallel: 3 keep_seed: true + until: world.stop_sim() { + method exploration; + reflex end_of_runs { do check("until_parallel"); } +} + +// 2. Many short simulations, not kept: used to hang or leave simulations behind (#198, #282). +// The batch must finish by itself ("Batch over" in the status bar) and the experiment reflex must fire. +experiment many_not_kept parent: regression_abstract type: batch repeat: 100 parallel: 4 keep_simulations: false + until: world.stop_sim() { + method exploration; + reflex end_of_runs { write "many_not_kept | end of a run (simulations kept: " + length(simulations) + ")"; } +} + +// 3. 'with:' needs parameter names as strings; each run must use one of the given values. +experiment explicit_with parent: regression_abstract type: batch repeat: 3 keep_seed: true + until: world.stop_sim() { + method exploration with: [["p"::0.2], ["p"::0.4], ["p"::0.8]]; + reflex end_of_runs { + bool p_ok <- simulations all_match (each.p in [0.2, 0.4, 0.8]); + write "explicit_with | parameters taken from the plan: " + (p_ok ? "PASS" : "FAIL"); + do check("explicit_with"); + } +} + +// 4. A 'permanent' section must be closed and reopened when the experiment is reloaded (#199). +experiment permanent_reload parent: regression_abstract type: batch repeat: 3 until: world.stop_sim() { + method exploration; + permanent { + display Cycles type: 2d { + chart "Cycles" type: series { + data "Max" value: max(simulations collect each.cycle) color: #red; + } + } + } +} diff --git a/gama.extension.batch/tests/models/BatchAdvancedTest.experiment b/gama.extension.batch/models/Batch Tests/BatchAdvancedTest.experiment similarity index 100% rename from gama.extension.batch/tests/models/BatchAdvancedTest.experiment rename to gama.extension.batch/models/Batch Tests/BatchAdvancedTest.experiment diff --git a/gama.extension.batch/tests/Exploration Tests/models/Exploration Facets Test.gaml b/gama.extension.batch/models/Batch Tests/Exploration Facets Test.gaml similarity index 83% rename from gama.extension.batch/tests/Exploration Tests/models/Exploration Facets Test.gaml rename to gama.extension.batch/models/Batch Tests/Exploration Facets Test.gaml index 73ac734964..7de9b54245 100644 --- a/gama.extension.batch/tests/Exploration Tests/models/Exploration Facets Test.gaml +++ b/gama.extension.batch/models/Batch Tests/Exploration Facets Test.gaml @@ -26,10 +26,6 @@ experiment "LHS Facet Test" type: batch { sample: 10 outer_iter: 20 inner_iter: 50; - - test "LHS Configuration" { - assert true; - } } // 2. Test Morris Facets @@ -38,10 +34,7 @@ experiment "Morris Facet Test" type: batch { parameter "p2" var: p2 min: 0.0 max: 1.0; method morris levels: 4 sample: 4 outputs: ["nb_preys"] report: "morris_report.txt"; - - test "Morris Configuration" { - assert true; - } + } // 3. Test With Facet (Direct Data) @@ -51,19 +44,11 @@ experiment "With Facet Test" type: batch { list> my_plan <- [["p1"::0.1], ["p1"::0.5], ["p1"::0.9]]; method exploration with: my_plan; - - test "With Configuration" { - assert true; - } } // 4. Test Default Sample Size experiment "Default Sample Test" type: batch { parameter "p1" var: p1 min: 0.0 max: 1.0; - method exploration sampling: "latinhypercube"; - - test "Default Size is 255" { - assert true; - } + method exploration sampling: "latinhypercube" sample: 132; } diff --git a/gama.extension.batch/models/Batch Tests/README.md b/gama.extension.batch/models/Batch Tests/README.md new file mode 100644 index 0000000000..795ef63c54 --- /dev/null +++ b/gama.extension.batch/models/Batch Tests/README.md @@ -0,0 +1,21 @@ +# Batch regression models + +Not automated: open `Batch Regression.gaml`, run each experiment and read the +console. Experiments with checks print `PASS`/`FAIL` lines. + +| Experiment | Verifies | Expected | +|---|---|---| +| `until_sequential`, `until_parallel` | each simulation stops on its **own** `until` (#198, #358, #418) | only `PASS` | +| `many_not_kept` | 100 short simulations, `parallel: 4`, `keep_simulations: false` finish; the end-of-run reflex fires (#198, #282) | batch ends by itself; status bar shows "Batch over" | +| `explicit_with` | `method exploration with:` plans (string keys) really apply the parameters | only `PASS` | +| `permanent_reload` | reload closes the old `permanent` display and opens the new one (#199) | one chart only, after several reloads | + +Manual checks not expressible in GAML: + +- **Threads (#282)**: during/after `many_not_kept`, the number of `Thread of Simulation …` threads (jstack, or the Eclipse + debug view) must stay about `parallel` and drop to 0 when the batch ends; the JVM/GAMA must not hang when closing. +- **Status bar (#325)**: shows `N simulations finished | R running | W waiting (using T threads)`, updating as it runs. +- **Pause / resume / stop** a running batch: no hung threads. +- **Failing model**: add `reflex boom when: cycle = 3 { int i <- 1 / 0; }` to `global`; the error must appear in the GAMA + error view and the failing simulation must stop (no endless "running" at the same cycle). +- Compare `exhaustive_exploration` and `explicit_exploration` in `models/Batch Simulation/Exploration.gaml`. diff --git a/gama.extension.batch/plugin.xml b/gama.extension.batch/plugin.xml index 15ed0b5f63..76125f84de 100644 --- a/gama.extension.batch/plugin.xml +++ b/gama.extension.batch/plugin.xml @@ -3,15 +3,6 @@ - - - - - - @@ -20,4 +11,10 @@ keyword="batch"> + + + + From c346a461edf5ce35a4c214a0393226f758770b32 Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sun, 11 Oct 2026 23:12:08 +0700 Subject: [PATCH 11/12] Merged main --- gama.extension.batch/plugin.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gama.extension.batch/plugin.xml b/gama.extension.batch/plugin.xml index 76125f84de..6a6bbc97eb 100644 --- a/gama.extension.batch/plugin.xml +++ b/gama.extension.batch/plugin.xml @@ -11,10 +11,4 @@ keyword="batch"> - - - - From 3294312584a9309800bb76d1e4ebf33b4a6e116c Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Mon, 12 Oct 2026 17:08:37 +0700 Subject: [PATCH 12/12] Fixes issues appeared when merging from main --- .../models/Batch Simulation/.project | 19 --- .../models/Batch Simulation/Calibration.gaml | 144 ----------------- .../models/Batch Simulation/Exploration.gaml | 148 ------------------ .../Batch Simulation/Results/exploration.csv | 31 ---- .../Batch Simulation/Results/preypredator.csv | 26 --- .../includes/ParameterSets.csv | 5 - .../models/Batch Simulation/results.csv | 19 --- .../Define Batch Experiments/Exploration.gaml | 5 - 8 files changed, 397 deletions(-) delete mode 100644 gama.extension.batch/models/Batch Simulation/.project delete mode 100644 gama.extension.batch/models/Batch Simulation/Calibration.gaml delete mode 100644 gama.extension.batch/models/Batch Simulation/Exploration.gaml delete mode 100644 gama.extension.batch/models/Batch Simulation/Results/exploration.csv delete mode 100644 gama.extension.batch/models/Batch Simulation/Results/preypredator.csv delete mode 100644 gama.extension.batch/models/Batch Simulation/includes/ParameterSets.csv delete mode 100644 gama.extension.batch/models/Batch Simulation/results.csv diff --git a/gama.extension.batch/models/Batch Simulation/.project b/gama.extension.batch/models/Batch Simulation/.project deleted file mode 100644 index 7e282e8e2a..0000000000 --- a/gama.extension.batch/models/Batch Simulation/.project +++ /dev/null @@ -1,19 +0,0 @@ - - - Batch Simulation - batch plugin - - - - - org.eclipse.xtext.ui.shared.xtextBuilder - - - - - - org.eclipse.xtext.ui.shared.xtextNature - gama.workspace.gamaNature - gama.workspace.pluginNature - - diff --git a/gama.extension.batch/models/Batch Simulation/Calibration.gaml b/gama.extension.batch/models/Batch Simulation/Calibration.gaml deleted file mode 100644 index eac939200f..0000000000 --- a/gama.extension.batch/models/Batch Simulation/Calibration.gaml +++ /dev/null @@ -1,144 +0,0 @@ -/** -* Name: Calibration -* Author: Patrick Taillandier -* Description: A comprehensive model showing how to use GAMA's batch experiment modes to calibrate and -* optimize a SIR epidemic model. The goal is to find the parameter combination that minimizes the number -* of infected agents. Seven optimization methods are demonstrated: Hill Climbing, Genetic Algorithm (GA), -* PSO (Particle Swarm Optimization), Tabu Search, Reactive Tabu Search, Simulated Annealing, and Explicit -* (exhaustive) exploration. Five experiments are provided: a GUI experiment, one that runs 10 replicates -* and saves data, and one dedicated experiment per optimization strategy. -* Tags: batch, algorithm, calibration, optimization, SIR, hill_climbing, GA, PSO, tabu, simulated_annealing -*/ - - -model batch_example - -global { - int number_people <- 100; // The init number of people - int number_I <- 5 ; // The init number of infected - float infection_rate <- 0.1 ; // The infection rate - float infection_distance <- 5.0 ; // infection distance (in meters) - float dying_proba <- 0.01; //probability to die at each step if infected - int immune_step <- 100 ; // number of steps before becoming immune after infection - float speed_people <- 5.0 ; // speed of the Host - - int num_dead <- 0; - init { - float t <- gama.machine_time; - create people number: number_people ; - ask (number_I among people) { - is_infected <- true; - color <- #red; - } - } - - reflex write_info when: time = 5000 { - write sample(infection_rate) + " " + sample(dying_proba) + " " +sample(seed) + " -> " + sample(num_dead); - } -} - -species people skills:[moving] { - bool is_infected <- false; - bool is_immune <- false; - rgb color <- #green; - int cpt <- 0; - reflex basic_move { - do wander(speed: speed_people); - } - - reflex die when: is_infected { - if flip(dying_proba) { - num_dead <- num_dead + 1; - do die(); - } - } - reflex become_immune when: is_infected { - if (cpt > immune_step) { - cpt <- 0; - is_immune <- true; - is_infected <- false; - color <- #blue; - } else { - cpt <- cpt + 1; - } - } - reflex become_infected when: not is_infected and not is_immune{ - if (flip(infection_rate) and not empty(people at_distance infection_distance where each.is_infected)) { - is_infected <- true; - color <- #red; - } - } - - aspect default { - draw circle(1) color: color; - } -} - -experiment Simple type:gui { - parameter 'Infection Rate:' var: infection_rate; - parameter 'Infection Distance:' var: infection_distance; - parameter 'Probability of dying:' var: dying_proba; - output { - monitor "nb of dead" value: num_dead; - display map { - species people aspect: default; - } - } -} - -// This experiment explores two parameters with a PSO strategy, -// repeating each simulation five times (the aggregated fitness correspond to the mean fitness), -// in order to find the best combination of parameters to minimize the number of infected people -experiment PSO type: batch keep_seed: true repeat: 5 until: ( time > 5000 ) { - parameter 'Infection rate' var: infection_rate min: 0.1 max:0.5 step:0.01; - parameter 'Probability of dying:' var: dying_proba min: 0.01 max: 0.2 step:0.01; - method pso num_particles: 5 weight_inertia:0.7 weight_cognitive: 1.5 weight_social: 1.5 iter_max: 5 aggregation:"avr" minimize: num_dead ; -} - -// This experiment explores two parameters with a GA strategy, -// repeating each simulation three times (the aggregated fitness correspond to the min fitness), -// in order to find the best combination of parameters to minimize the number of infected people -experiment Genetic type: batch keep_seed: true repeat: 3 until: ( time > 5000 ) { - parameter 'Infection rate' var: infection_rate min: 0.1 max:0.5 step:0.01; - parameter 'Probability of dying:' var: dying_proba min: 0.01 max: 0.2 step:0.01; - method genetic pop_dim: 3 crossover_prob: 0.7 mutation_prob: 0.1 improve_sol: true stochastic_sel: false - nb_prelim_gen: 1 max_gen: 5 minimize: num_dead aggregation: "min"; -} - - -// This experiment explores two parameters with a Hill Climbing strategy from an explicit init solution (if no solution is given, start from a random sol), -// repeating each simulation three times (the aggregated fitness correspond to the max fitness), -// in order to find the best combination of parameters to minimize the number of infected people -experiment Hill_Climbing type: batch keep_seed: true repeat: 3 until: ( time > 5000 ) { - parameter 'Infection rate' var: infection_rate min: 0.1 max:0.5 step:0.1; - parameter 'Probability of dying:' var: dying_proba min: 0.01 max: 0.2 step:0.01; - method hill_climbing init_solution:map(["infection_rate"::0.2, "dying_proba":: 0.05]) minimize: num_dead aggregation: "max"; -} - - -// This experiment explores two parameters with a Tabu Search strategy, -// repeating each simulation three times (the aggregated fitness correspond to the max fitness), -// in order to find the best combination of parameters to minimize the number of infected people -experiment Tabu_Search type: batch keep_seed: true repeat: 3 until: ( time > 5000 ) { - parameter 'Infection rate' var: infection_rate min: 0.1 max:0.5 step:0.01; - parameter 'Probability of dying:' var: dying_proba min: 0.01 max: 0.2 step:0.01; - method tabu iter_max: 5 tabu_list_size: 5 minimize: num_dead aggregation: "max"; -} - -// This experiment explores two parameters with a Reactive Tabu Search strategy, -// repeating each simulation three times (the aggregated fitness correspond to the max fitness), -// in order to find the best combination of parameters to minimize the number of infected people -experiment Reactive_Tabu_Search type: batch keep_seed: true repeat: 3 until: ( time > 5000 ) { - parameter 'Infection rate' var: infection_rate min: 0.1 max:0.5 step:0.01; - parameter 'Probability of dying:' var: dying_proba min: 0.01 max: 0.2 step:0.01; - method reactive_tabu iter_max: 10 cycle_size_max: 10 cycle_size_min: 3 tabu_list_size_init: 5 minimize: num_dead aggregation: "max"; -} - -// This experiment explores two parameters with a Simulated annealing strategy, -// repeating each simulation three times (the aggregated fitness correspond to the max fitness), -// in order to find the best combination of parameters to minimize the number of infected people -experiment Simulated_annealing type: batch keep_seed: true repeat: 3 until: ( time > 5000 ) { - parameter 'Infection rate' var: infection_rate min: 0.1 max:0.5 step:0.01; - parameter 'Probability of dying:' var: dying_proba min: 0.01 max: 0.2 step:0.01; - method annealing minimize: num_dead temp_decrease: 0.5 temp_end: 10.0 temp_init: 50; -} \ No newline at end of file diff --git a/gama.extension.batch/models/Batch Simulation/Exploration.gaml b/gama.extension.batch/models/Batch Simulation/Exploration.gaml deleted file mode 100644 index d44af2e492..0000000000 --- a/gama.extension.batch/models/Batch Simulation/Exploration.gaml +++ /dev/null @@ -1,148 +0,0 @@ -/** -* Name: Exploration -* Author: Kevin Chapuis -* Description: A model exploration example built on top of the Predator Prey tutorial (Model 13). Defines -* multiple batch experiment types for systematic parameter space exploration: exhaustive exploration -* (all combinations), Latin Hypercube Sampling (LHS), and method-specific exploration strategies. The -* model imports the base predator-prey model and adds exploration experiment definitions on top, keeping -* the base model untouched. This is the standard reference for parameter sensitivity analysis and model -* exploration in GAMA. -* Tags: batch, exploration, sensitivity_analysis, LHS, parameter_space, predator_prey -*/ - - -model Exploration - -import "../Predator Prey/models/Model 13.gaml" - - -/* - * Change a little bit the behavior of the world agent to fit exploration requirements - */ -global { - int end_cycle <- 500; - reflex save_result when: (nb_preys > 0) and (nb_predators > 0){ } // Overload method so we do not have any saved output - bool stop_sim() { float tmp <- time; return (nb_preys = 0) or (nb_predators = 0); } -} - -/* - * Model used to expose simulation exploration capabilities of Gama batch experiments - * ---- - * See Predator Prey in tutorial in the Model Library - * - */ - -experiment batch_abstract type:batch virtual:true until:(time > end_cycle) { - init {is_batch <- true;} - parameter "Prey max transfer:" var: prey_max_transfer min: 0.05 max: 0.5 step: 0.05; - parameter "Prey energy reproduce:" var: prey_energy_reproduce min: 0.05 max: 0.75 step: 0.05; - parameter "Predator energy transfer:" var: predator_energy_transfer min: 0.1 max: 1.0 step: 0.1; - parameter "Predator energy reproduce:" var: predator_energy_reproduce min: 0.1 max: 1.0 step: 0.1; -} - -// This experiment runs the full factorial experiment (each combination of parameter) 5 times, that is 14k simulations :) see exhaustive_exploration experiment -// At the end of each simulation (replicated 5 times), the people agents are saved in a shapefile -experiment 'Run every possible simulation 5 times' parent: batch_abstract type: batch repeat: 5 keep_seed: true until: world.stop_sim() or (time > end_cycle){ - - // the reflex will be activated at the end of each run; in this experiment a run consists of the execution of 5 simulations (repeat: 5) - reflex end_of_runs - { - int cpt <- 0; - // each simulation of the run is an agent; it is possible to access to the list of these agents by using the variable "simulations" of the experiment. - // Another way of accessing to the simulations consists in using the name of model + _model: here "batch_example_model" - //in this example, we ask all the simulation agents of the run to save (at the end of the simulation) the people population in a shapefile with their is_infected and is_immune attributes - ask simulations - { - save [nb_preys,nb_predators] to: "Results/preypredator.csv" format:"csv" rewrite:false; - } - } -} - -// This experiment extract the number of replicates that should be made according to two methods: -// 1. How increasing the number of replicates dimish the standard error -// 2. coefficient of variation -experiment replication_analysis parent: batch_abstract type: batch until: world.stop_sim() or ( time > end_cycle ) - repeat:40 keep_simulations:false { - method stochanalyse outputs:[nb_preys, nb_predators] report:"Results/stochanalysis.csv" results:"Results/stochanalysis_raw.csv" sample:3; -} - -// This experiment explores the four parameters with an exhaustive strategy (default sampling method for exploration), -// repeating each simulation three times. The overall combination of parameter values is 14000. -// This is what we call 'brute force' exploration - because obviously it is not smart, nor gentle in the exploration approach. -// In order to diminish number of explored points, one can use 'factorial' facet (how many value per parameter) or diminish the step -// facet of parameters each at a time. Another way is to rely on smarter strategy to sample from the parameter space using sampling methods. -experiment exhaustive_exploration parent: batch_abstract type: batch keep_seed: true until: world.stop_sim() or ( time > end_cycle ) { - method exploration; - - //the permanent section allows to define a output section that will be kept during all the batch experiment - permanent { - display Comparison type: 2d { - chart "Number of people infected" type: series { - //we can access to all the simulations of a run (here composed of 5 simulation -> repeat: 5) by the variable "simulations" of the experiment. - //here we display for the 5 simulations, the mean, min and max values of the nb_infected variable. - data "Mean" value: mean(simulations collect each.nb_preys ) style: spline color: #blue ; - data "Min" value: min(simulations collect each.nb_preys ) style: spline color: #darkgreen ; - data "Max" value: max(simulations collect each.nb_preys ) style: spline color: #red ; - } - } - } -} - -// This experiment tests explicit parameters sets combining 2 parameters in 4 different configurations, -// repeating each simulation three times (the aggregated fitness correspond to the mean fitness), -experiment explicit_exploration parent: batch_abstract type: batch repeat: 3 keep_seed: true until: world.stop_sim() or ( time > end_cycle ) { - method exploration with: [ - ["prey_max_transfer"::0.1, "predator_energy_transfer":: 0.1], - ["prey_max_transfer"::0.5, "predator_energy_transfer":: 0.2], - ["prey_max_transfer"::1.0, "predator_energy_transfer":: 0.5], - ["prey_max_transfer"::0.5, "predator_energy_transfer":: 0.1] - ]; -} - -// Conducted the same experiment plan but explicitly defined using a csv file -experiment explicit_from_file parent: batch_abstract type: batch repeat: 3 keep_seed: true until: world.stop_sim() or ( time > end_cycle ) { - method exploration from:"includes/ParameterSets.csv" outputs:[nb_preys,nb_predators,time] results:"Results/exploration.csv"; -} - -// This experiment iterate over point of the parameter space choosen following -// Latin Hypercube Sampling -experiment exploration_with_sampling parent: batch_abstract repeat:3 type: batch until:world.stop_sim() or time>end_cycle { - method exploration sampling:"latinhypercube" sample:100; -} - -experiment exploration_with_factorial parent: batch_abstract repeat:3 type: batch until:world.stop_sim() or time>end_cycle { - method exploration sampling:"factorial" factorial:4 sample:100; -} - -// This experiment iterate over 100 point randomly drawn from the parameter space -// Then the model global variables "nb_preys" and "nb_predators" are saved un a csv for each simulation run (including potential replicates) -experiment exploration_with_sampling_and_outputs parent: batch_abstract repeat:3 type: batch until:world.stop_sim() or time>end_cycle { - method exploration sampling:"uniform" sample:10 outputs:[nb_preys,nb_predators,time] results:"Results/exploration.csv"; -} - -// This experiment samples from the parameter space (Saltelli methods) to establish -// Sobol index, i.e. a contribution value of each parameters to -// observed variance for outcomes of interest, -// more on this see https://www.jasss.org/19/1/5.html and http://moeaframework.org for the API -experiment Sobol parent: batch_abstract type: batch until:( time > end_cycle ) { - method sobol outputs:[nb_preys,nb_predators] sample:10 report:"Results/sobol.csv" results:"Results/sobol_raw.csv"; -} - -// This experiment perform a Morris analysis (see Morris 1991, doi:10.1080/00401706.1991.10484804) -// to screen and rank parameters based on elementary effect (changes on outputs due to a small modification of -// one paameter value) -experiment Morris parent: batch_abstract type: batch until:( time > end_cycle ) { - method morris outputs:[nb_preys,nb_predators] sample:10 levels:4 report:"Results/morris.csv" results:"Results/morris_raw.csv"; -} - -// This experiment computed beta d kuiper statistics to estimate the impact of parameters -// on the distribution of outputs. It has been retro-engineered based on the description in -// Borgonovo et al. 2022 doi:10.1007/s10588-021-09358-5 -// --------------- -// sample facet: number of sampled points -// bootstrap facet: how many time a parameter value is duplicated in the final experiment plan, with bootstrap < sample -// Hence, final sample size is 'sample + sample * bootstrap * |parameter|', with default sample and bootstrap, respectively 132 and 4 -// Sampled point should be high and at least 2 times higher than bootstrap -experiment Beta_distribution parent: batch_abstract type: batch until:( time > end_cycle ) { - method betad outputs:[nb_preys,nb_predators] sampling:"uniform" sample:10 bootstrap:4 report:"Results/betad.csv" results:"Results/betad_raw.csv"; -} \ No newline at end of file diff --git a/gama.extension.batch/models/Batch Simulation/Results/exploration.csv b/gama.extension.batch/models/Batch Simulation/Results/exploration.csv deleted file mode 100644 index 313deeb152..0000000000 --- a/gama.extension.batch/models/Batch Simulation/Results/exploration.csv +++ /dev/null @@ -1,31 +0,0 @@ -prey_max_transfer,prey_energy_reproduce,predator_energy_transfer,predator_energy_reproduce,nb_preys,nb_predators,time -0.3829552836740046,0.6155660444737817,0.5771142786311795,0.5439461617119986,3,0,181.0 -0.3829552836740046,0.6155660444737817,0.5771142786311795,0.5439461617119986,21,0,224.0 -0.3829552836740046,0.6155660444737817,0.5771142786311795,0.5439461617119986,3,0,247.0 -0.47797887506927056,0.08555954031288505,0.7774029323599276,0.23868310957115263,1,0,122.0 -0.47797887506927056,0.08555954031288505,0.7774029323599276,0.23868310957115263,19,0,132.0 -0.47797887506927056,0.08555954031288505,0.7774029323599276,0.23868310957115263,88,17,501.0 -0.34330881432750465,0.10147626416873289,0.6125616373642396,0.4840228627530946,79,16,501.0 -0.34330881432750465,0.10147626416873289,0.6125616373642396,0.4840228627530946,77,13,501.0 -0.34330881432750465,0.10147626416873289,0.6125616373642396,0.4840228627530946,154,3,501.0 -0.26763879791591855,0.12540836684339102,0.4457315865171779,0.587623718536298,37,0,133.0 -0.26763879791591855,0.12540836684339102,0.4457315865171779,0.587623718536298,20,10,501.0 -0.26763879791591855,0.12540836684339102,0.4457315865171779,0.587623718536298,59,7,501.0 -0.38500912811399424,0.7170563395173344,0.9346652850043696,0.9477721270649239,23,0,183.0 -0.38500912811399424,0.7170563395173344,0.9346652850043696,0.9477721270649239,62,9,501.0 -0.38500912811399424,0.7170563395173344,0.9346652850043696,0.9477721270649239,69,9,501.0 -0.3859723419446254,0.4130643333041754,0.5866267099934919,0.30031186080660355,10,0,136.0 -0.3859723419446254,0.4130643333041754,0.5866267099934919,0.30031186080660355,63,4,501.0 -0.3859723419446254,0.4130643333041754,0.5866267099934919,0.30031186080660355,84,10,501.0 -0.4113867622966763,0.36682782626316485,0.9778677422918179,0.7601735734215916,0,10,89.0 -0.4113867622966763,0.36682782626316485,0.9778677422918179,0.7601735734215916,0,21,101.0 -0.4113867622966763,0.36682782626316485,0.9778677422918179,0.7601735734215916,0,21,108.0 -0.11906139365958134,0.4697449116948781,0.15770766476920034,0.5242876596264772,33,0,136.0 -0.11906139365958134,0.4697449116948781,0.15770766476920034,0.5242876596264772,23,0,192.0 -0.11906139365958134,0.4697449116948781,0.15770766476920034,0.5242876596264772,12,0,211.0 -0.2289220055842472,0.25678930642498177,0.6164808478019536,0.6824663700021785,0,29,70.0 -0.2289220055842472,0.25678930642498177,0.6164808478019536,0.6824663700021785,0,7,112.0 -0.2289220055842472,0.25678930642498177,0.6164808478019536,0.6824663700021785,38,0,214.0 -0.42339219328860683,0.578282140901726,0.1493629995882695,0.7712213534201516,20,0,120.0 -0.42339219328860683,0.578282140901726,0.1493629995882695,0.7712213534201516,18,0,144.0 -0.42339219328860683,0.578282140901726,0.1493629995882695,0.7712213534201516,46,8,501.0 \ No newline at end of file diff --git a/gama.extension.batch/models/Batch Simulation/Results/preypredator.csv b/gama.extension.batch/models/Batch Simulation/Results/preypredator.csv deleted file mode 100644 index f2d4bac071..0000000000 --- a/gama.extension.batch/models/Batch Simulation/Results/preypredator.csv +++ /dev/null @@ -1,26 +0,0 @@ -nb_preys,nb_predators -23,0 -38,0 -21,0 -23,0 -29,0 -26,0 -17,0 -3,0 -28,0 -7,0 -53,0 -22,0 -23,0 -13,0 -1,0 -21,0 -2,0 -19,0 -42,0 -1,0 -26,0 -41,0 -8,0 -79,0 -24,0 diff --git a/gama.extension.batch/models/Batch Simulation/includes/ParameterSets.csv b/gama.extension.batch/models/Batch Simulation/includes/ParameterSets.csv deleted file mode 100644 index 1222b232a4..0000000000 --- a/gama.extension.batch/models/Batch Simulation/includes/ParameterSets.csv +++ /dev/null @@ -1,5 +0,0 @@ -prey_max_transfer,predator_energy_transfer -0.1,0.01 -0.5,0.2 -1.0,0.05 -0.5,0.1 \ No newline at end of file diff --git a/gama.extension.batch/models/Batch Simulation/results.csv b/gama.extension.batch/models/Batch Simulation/results.csv deleted file mode 100644 index 81d5458c4f..0000000000 --- a/gama.extension.batch/models/Batch Simulation/results.csv +++ /dev/null @@ -1,19 +0,0 @@ -int(self),prey_max_transfer,prey_energy_reproduce,predator_energy_transfer,predator_energy_reproduce,self.nb_predators,self.nb_preys -0,0.25,0.15,0.3,0.5,5,76 -1,0.25,0.15,0.3,0.5,0,128 -2,0.2,0.15,0.3,0.5,1,14 -3,0.2,0.15,0.3,0.5,0,58 -4,0.3,0.15,0.3,0.5,0,0 -5,0.3,0.15,0.3,0.5,4,144 -6,0.25,0.1,0.3,0.5,0,22 -7,0.25,0.1,0.3,0.5,1,59 -8,0.25,0.2,0.3,0.5,1,83 -9,0.25,0.2,0.3,0.5,3,204 -10,0.25,0.15,0.2,0.5,0,10 -11,0.25,0.15,0.2,0.5,0,74 -12,0.25,0.15,0.4,0.5,0,40 -13,0.25,0.15,0.4,0.5,0,0 -14,0.25,0.15,0.3,0.4,2,127 -15,0.25,0.15,0.3,0.4,0,66 -16,0.25,0.15,0.3,0.6,0,116 -17,0.25,0.15,0.3,0.6,4,16 diff --git a/gama.extension.batch/models/Recipes/Define Batch Experiments/Exploration.gaml b/gama.extension.batch/models/Recipes/Define Batch Experiments/Exploration.gaml index 4853e7eae2..2e3e974539 100644 --- a/gama.extension.batch/models/Recipes/Define Batch Experiments/Exploration.gaml +++ b/gama.extension.batch/models/Recipes/Define Batch Experiments/Exploration.gaml @@ -13,12 +13,7 @@ model Exploration -<<<<<<<< HEAD:gama.extension.batch/models/Batch Simulation/Exploration.gaml -import "../Predator Prey/models/Model 13.gaml" - -======== import "../Predator Prey Tutorial/models/Model 13.gaml" ->>>>>>>> main:gama.extension.batch/models/Recipes/Define Batch Experiments/Exploration.gaml /* * Change a little bit the behavior of the world agent to fit exploration requirements