diff --git a/src/arcade/core/util/EventLog.java b/src/arcade/core/util/EventLog.java
new file mode 100644
index 000000000..483992965
--- /dev/null
+++ b/src/arcade/core/util/EventLog.java
@@ -0,0 +1,37 @@
+package arcade.core.util;
+
+import java.util.Map;
+
+/**
+ * Abstract class representing a logged simulation event.
+ *
+ *
{@code EventLog} objects capture specific events that occur during a simulation, recording
+ * when the event happened and what type of event it was. Subclasses define the specific details of
+ * each event type.
+ */
+public abstract class EventLog {
+
+ /** The timestep at which this log was created. */
+ public final int timestamp;
+
+ /** A String identifier representing the type of event that was logged. */
+ public final String eventType;
+
+ /**
+ * Constructs an {@code EventLog} with the given timestamp and event type.
+ *
+ * @param timestamp the simulation timestep at which the event occurred
+ * @param eventType a String identifier representing the type of event
+ */
+ public EventLog(int timestamp, String eventType) {
+ this.timestamp = timestamp;
+ this.eventType = eventType;
+ }
+
+ /**
+ * Returns a map of key-value pairs describing the details of this event.
+ *
+ * @return a Map containing the event's details
+ */
+ public abstract Map eventDetails();
+}
diff --git a/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java b/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java
index 6c4563206..756d2ba4a 100644
--- a/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java
+++ b/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java
@@ -1,7 +1,5 @@
package arcade.patch.agent.module;
-import java.util.HashMap;
-import java.util.Map;
import ec.util.MersenneTwisterFast;
import arcade.core.sim.Simulation;
import arcade.core.util.Parameters;
@@ -11,10 +9,9 @@
import arcade.patch.agent.process.PatchProcessInflammation;
import arcade.patch.env.location.PatchLocation;
import arcade.patch.sim.PatchSimulation;
+import arcade.patch.util.LysisEventLog;
import arcade.patch.util.PatchEnums.Domain;
import arcade.patch.util.PatchEnums.State;
-import static arcade.patch.util.PatchEnums.Domain;
-import static arcade.patch.util.PatchEnums.State;
/**
* Implementation of {@link Module} for killing tissue agents.
@@ -77,16 +74,14 @@ public void step(MersenneTwisterFast random, Simulation sim) {
// Log cytotoxicity event
PatchSimulation patchSim = (PatchSimulation) sim;
- Map eventData = new HashMap<>();
- eventData.put("type", "lysis");
- eventData.put("timestamp", (int) ((PatchSimulation) sim).getSchedule().getTime());
- eventData.put("cell-id", cell.getID());
- eventData.put("target-cell-id", target.getID());
- eventData.put("target-cell-type", target.getPop());
- eventData.put(
- "target-cell-location",
- ((PatchLocation) target.getLocation()).getCoordinate());
- patchSim.logEvent(eventData);
+ LysisEventLog eventLog =
+ new LysisEventLog(
+ (int) sim.getSchedule().getTime(),
+ cell.getID(),
+ target.getID(),
+ target.getPop(),
+ ((PatchLocation) target.getLocation()).getCoordinate());
+ patchSim.logEvent(eventLog.eventDetails());
}
}
diff --git a/src/arcade/patch/agent/module/PatchModuleProliferation.java b/src/arcade/patch/agent/module/PatchModuleProliferation.java
index 0e6917cbb..98dead85d 100644
--- a/src/arcade/patch/agent/module/PatchModuleProliferation.java
+++ b/src/arcade/patch/agent/module/PatchModuleProliferation.java
@@ -1,7 +1,5 @@
package arcade.patch.agent.module;
-import java.util.HashMap;
-import java.util.Map;
import sim.util.Bag;
import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.CellContainer;
@@ -17,8 +15,7 @@
import arcade.patch.sim.PatchSimulation;
import arcade.patch.util.PatchEnums.Domain;
import arcade.patch.util.PatchEnums.State;
-import static arcade.patch.util.PatchEnums.Domain;
-import static arcade.patch.util.PatchEnums.State;
+import arcade.patch.util.ProliferationEventLog;
/**
* Extension of {@link PatchModule} for proliferation.
@@ -133,13 +130,10 @@ public void step(MersenneTwisterFast random, Simulation sim) {
// Log proliferation event
PatchSimulation patchSim = (PatchSimulation) sim;
- Map eventData = new HashMap<>();
- eventData.put("type", "proliferation");
- eventData.put(
- "timestamp", (int) ((PatchSimulation) sim).getSchedule().getTime());
- eventData.put("cell-id", cell.getID());
- eventData.put("cycle-length", duration);
- patchSim.logEvent(eventData);
+ ProliferationEventLog eventLog =
+ new ProliferationEventLog(
+ (int) sim.getSchedule().getTime(), cell.getID(), duration);
+ patchSim.logEvent(eventLog.eventDetails());
// TODO: Update environment generator sites.
} else {
diff --git a/src/arcade/patch/util/LysisEventLog.java b/src/arcade/patch/util/LysisEventLog.java
new file mode 100644
index 000000000..c64254ba8
--- /dev/null
+++ b/src/arcade/patch/util/LysisEventLog.java
@@ -0,0 +1,74 @@
+package arcade.patch.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import arcade.core.util.EventLog;
+import arcade.patch.env.location.Coordinate;
+
+/**
+ * Concrete implementation of {@link EventLog} for lysis events.
+ *
+ * {@code LysisEventLog} objects are created when a CD8 CAR T-cell successfully kills a target
+ * tissue cell, capturing the ID, type, and location of the target cell at the time of lysis, as
+ * well as the ID of the CAR T-cell and the time at which lysis occurred.
+ */
+public class LysisEventLog extends EventLog {
+
+ /** The event type identifier for lysis events. */
+ public static final String EVENT_TYPE = "lysis";
+
+ /** The ID of the cell that performed the lysis. */
+ public final int cellId;
+
+ /** The ID of the cell that underwent lysis. */
+ public final int targetCellId;
+
+ /** The type of the cell that underwent lysis. */
+ public final int targetCellType;
+
+ /** The location of the cell underwent lysis, at the time of lysis. */
+ public final Coordinate targetCellLocation;
+
+ /**
+ * Constructs a {@code LysisEventLog} with the given event details.
+ *
+ * @param timestamp the simulation timestep at which lysis occurred
+ * @param cellId the ID of the cell that performed the lysis
+ * @param targetCellId the ID of the cell that underwent lysis
+ * @param targetCellType the type of the cell that underwent lysis
+ * @param targetCellLocation the location of the cell underwent lysis, at the time of lysis
+ */
+ public LysisEventLog(
+ int timestamp,
+ int cellId,
+ int targetCellId,
+ int targetCellType,
+ Coordinate targetCellLocation) {
+
+ super(timestamp, EVENT_TYPE);
+ this.cellId = cellId;
+ this.targetCellId = targetCellId;
+ this.targetCellType = targetCellType;
+ this.targetCellLocation = targetCellLocation;
+ }
+
+ /**
+ * Returns a map of key-value pairs describing the details of this lysis event.
+ *
+ *
The map includes the event type, timestamp, the ID of the cell that performed lysis, and
+ * the ID, type, and location of the target cell that underwent lysis.
+ *
+ * @return a Map containing the lysis event's details
+ */
+ @Override
+ public Map eventDetails() {
+ Map map = new HashMap<>();
+ map.put("event-type", EVENT_TYPE);
+ map.put("timestamp", super.timestamp);
+ map.put("cell-id", cellId);
+ map.put("target-cell-id", targetCellId);
+ map.put("target-cell-type", targetCellType);
+ map.put("target-cell-location", targetCellLocation);
+ return map;
+ }
+}
diff --git a/src/arcade/patch/util/ProliferationEventLog.java b/src/arcade/patch/util/ProliferationEventLog.java
new file mode 100644
index 000000000..72b7cbb35
--- /dev/null
+++ b/src/arcade/patch/util/ProliferationEventLog.java
@@ -0,0 +1,57 @@
+package arcade.patch.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import arcade.core.util.EventLog;
+
+/**
+ * Concrete implementation of {@link EventLog} for proliferation events.
+ *
+ * {@code ProliferationEventLog} objects are created when a cell successfully completes its cell
+ * cycle and divides, capturing the ID of the dividing cell and the duration of its cell cycle, as
+ * well as the time at which proliferation occurred.
+ */
+public class ProliferationEventLog extends EventLog {
+
+ /** The event type identifier for proliferation events. */
+ public static final String EVENT_TYPE = "proliferation";
+
+ /** The ID of the cell that proliferated. */
+ public final int cellId;
+
+ /** The duration of the cell cycle from the start of proliferation to division. */
+ public final int cycleLength;
+
+ /**
+ * Constructs a {@code ProliferationEventLog} with the given event details.
+ *
+ * @param timestamp the simulation timestep at which proliferation occurred
+ * @param cellId the ID of the cell that proliferated.
+ * @param cycleLength the duration of the cell cycle from the start of proliferation to
+ * division.
+ */
+ public ProliferationEventLog(int timestamp, int cellId, int cycleLength) {
+
+ super(timestamp, EVENT_TYPE);
+ this.cellId = cellId;
+ this.cycleLength = cycleLength;
+ }
+
+ /**
+ * Returns a map of key-value pairs describing the details of this proliferation event.
+ *
+ *
The map includes the event type, timestamp, the ID of the cell that proliferated, and the
+ * duration of the cell cycle from the start of proliferation to division.
+ *
+ * @return a Map containing the proliferation event's details
+ */
+ @Override
+ public Map eventDetails() {
+ Map map = new HashMap<>();
+ map.put("event-type", EVENT_TYPE);
+ map.put("timestamp", super.timestamp);
+ map.put("cell-id", cellId);
+ map.put("cycle-length", cycleLength);
+ return map;
+ }
+}
diff --git a/test/arcade/core/util/EventLogTest.java b/test/arcade/core/util/EventLogTest.java
new file mode 100644
index 000000000..e7319c984
--- /dev/null
+++ b/test/arcade/core/util/EventLogTest.java
@@ -0,0 +1,27 @@
+package arcade.core.util;
+
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+public class EventLogTest {
+
+ static class EventLogMock extends EventLog {
+ EventLogMock(int timestamp, String eventType) {
+ super(timestamp, eventType);
+ }
+
+ @Override
+ public Map eventDetails() {
+ return mock(Map.class);
+ }
+ }
+
+ @Test
+ public void constructor_called_setsAllFields() {
+ EventLog log = new EventLogMock(10, "TEST_EVENT");
+ assertEquals(10, log.timestamp);
+ assertEquals("TEST_EVENT", log.eventType);
+ }
+}
diff --git a/test/arcade/patch/util/LysisEventLogTest.java b/test/arcade/patch/util/LysisEventLogTest.java
new file mode 100644
index 000000000..af4ff5f6f
--- /dev/null
+++ b/test/arcade/patch/util/LysisEventLogTest.java
@@ -0,0 +1,36 @@
+package arcade.patch.util;
+
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import arcade.patch.env.location.Coordinate;
+import arcade.patch.env.location.CoordinateXYZ;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class LysisEventLogTest {
+
+ private static final Coordinate COORDINATE = (Coordinate) new CoordinateXYZ(0, 1, 2);
+
+ private static final LysisEventLog LOG = new LysisEventLog(10, 1, 2, 3, COORDINATE);
+
+ @Test
+ public void constructor_called_setsAllFields() {
+ assertEquals(10, LOG.timestamp);
+ assertEquals("lysis", LOG.eventType);
+ assertEquals(1, LOG.cellId);
+ assertEquals(2, LOG.targetCellId);
+ assertEquals(3, LOG.targetCellType);
+ assertEquals(COORDINATE, LOG.targetCellLocation);
+ }
+
+ @Test
+ public void eventDetails_containsAllFields() {
+ Map details = LOG.eventDetails();
+ assertEquals(6, details.size());
+ assertEquals("lysis", details.get("event-type"));
+ assertEquals(10, details.get("timestamp"));
+ assertEquals(1, details.get("cell-id"));
+ assertEquals(2, details.get("target-cell-id"));
+ assertEquals(3, details.get("target-cell-type"));
+ assertEquals(COORDINATE, details.get("target-cell-location"));
+ }
+}
diff --git a/test/arcade/patch/util/ProliferationEventLogTest.java b/test/arcade/patch/util/ProliferationEventLogTest.java
new file mode 100644
index 000000000..eb780359d
--- /dev/null
+++ b/test/arcade/patch/util/ProliferationEventLogTest.java
@@ -0,0 +1,28 @@
+package arcade.patch.util;
+
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class ProliferationEventLogTest {
+
+ private static final ProliferationEventLog LOG = new ProliferationEventLog(10, 1, 100);
+
+ @Test
+ public void constructor_called_setsAllFields() {
+ assertEquals(10, LOG.timestamp);
+ assertEquals("proliferation", LOG.eventType);
+ assertEquals(1, LOG.cellId);
+ assertEquals(100, LOG.cycleLength);
+ }
+
+ @Test
+ public void eventDetails_containsAllFields() {
+ Map details = LOG.eventDetails();
+ assertEquals(4, details.size());
+ assertEquals("proliferation", details.get("event-type"));
+ assertEquals(10, details.get("timestamp"));
+ assertEquals(1, details.get("cell-id"));
+ assertEquals(100, details.get("cycle-length"));
+ }
+}