From ffac9c2819bbc66059cacdea5719b9882cd97a89 Mon Sep 17 00:00:00 2001 From: Nicolas Payette Date: Mon, 3 Feb 2025 19:35:24 +0000 Subject: [PATCH] add a standard biomass hold and a proportional discarding strategy --- .../ox/poseidon/agents/vessels/hold/Hold.java | 2 + .../agents/vessels/hold/InfiniteHold.java | 11 ++ .../hold/OvercapacityDiscardingStrategy.java | 39 +++++ ...BiomassOvercapacityDiscardingStrategy.java | 54 ++++++ ...OvercapacityDiscardingStrategyFactory.java | 35 ++++ .../vessels/hold/StandardBiomassHold.java | 67 ++++++++ .../hold/StandardBiomassHoldFactory.java | 60 +++++++ .../agents/vessels/hold/VoidHold.java | 10 ++ ...assOvercapacityDiscardingStrategyTest.java | 161 ++++++++++++++++++ .../uk/ac/ox/poseidon/biology/Bucket.java | 9 +- .../ox/poseidon/biology/biomass/Biomass.java | 12 ++ .../UniformCarryingCapacityGridFactory.java | 9 +- .../quantities/AbstractQuantityFactory.java | 8 + .../ox/poseidon/examples/BasicScenario.java | 15 +- 14 files changed, 482 insertions(+), 10 deletions(-) create mode 100644 agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/OvercapacityDiscardingStrategy.java create mode 100644 agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategy.java create mode 100644 agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyFactory.java create mode 100644 agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHold.java create mode 100644 agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHoldFactory.java create mode 100644 agents/src/test/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyTest.java diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/Hold.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/Hold.java index 19764540a..9474ac9cb 100644 --- a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/Hold.java +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/Hold.java @@ -40,6 +40,8 @@ public interface Hold> { */ Bucket getContent(); + boolean isFull(); + /** * Removes all content currently held in the container and returns it. * diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/InfiniteHold.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/InfiniteHold.java index 19996d764..18c82e87a 100644 --- a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/InfiniteHold.java +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/InfiniteHold.java @@ -44,6 +44,17 @@ public Bucket getContent() { return content; } + /** + * An infinite hold is never full (though there might be technical limits depending on content + * type, e.g. Double.MAX_VALUE). + * + * @return false + */ + @Override + public boolean isFull() { + return false; + } + @Override public Bucket removeContent() { final Bucket result = content; diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/OvercapacityDiscardingStrategy.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/OvercapacityDiscardingStrategy.java new file mode 100644 index 000000000..b9f254ccb --- /dev/null +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/OvercapacityDiscardingStrategy.java @@ -0,0 +1,39 @@ +/* + * POSEIDON: an agent-based model of fisheries + * Copyright (c) 2025 CoHESyS Lab cohesys.lab@gmail.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package uk.ac.ox.poseidon.agents.vessels.hold; + +import lombok.Data; +import uk.ac.ox.poseidon.biology.Bucket; +import uk.ac.ox.poseidon.biology.Content; + +public interface OvercapacityDiscardingStrategy> { + Result discard( + Bucket contentToAdd, + Bucket currentHoldContent, + double capacityInKg, + double toleranceInKg + ); + + @Data + class Result> { + public final Bucket discarded; + public final Bucket updatedHoldContent; + } +} diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategy.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategy.java new file mode 100644 index 000000000..9a07c52e0 --- /dev/null +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategy.java @@ -0,0 +1,54 @@ +/* + * POSEIDON: an agent-based model of fisheries + * Copyright (c) 2025 CoHESyS Lab cohesys.lab@gmail.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package uk.ac.ox.poseidon.agents.vessels.hold; + +import uk.ac.ox.poseidon.biology.Bucket; +import uk.ac.ox.poseidon.biology.biomass.Biomass; + +public class ProportionalBiomassOvercapacityDiscardingStrategy + implements OvercapacityDiscardingStrategy { + @Override + public Result discard( + final Bucket contentToAdd, + final Bucket currentHoldContent, + final double capacityInKg, + final double toleranceInKg + ) { + final double contentToAddInKg = contentToAdd.getTotalBiomass().asKg(); + final double currentContentInKg = currentHoldContent.getTotalBiomass().asKg(); + final double availableCapacityInKg = capacityInKg - currentContentInKg; + if (contentToAddInKg <= availableCapacityInKg) { + return new Result<>( + Bucket.empty(), + currentHoldContent.add(contentToAdd) + ); + } else { + final double proportionToKeep = availableCapacityInKg / contentToAddInKg; + final Bucket contentToKeep = + contentToAdd.mapContent(biomass -> + biomass.multiply(proportionToKeep) + ); + return new Result<>( + contentToAdd.subtract(contentToKeep), + currentHoldContent.add(contentToKeep) + ); + } + } +} diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyFactory.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyFactory.java new file mode 100644 index 000000000..af23246e5 --- /dev/null +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyFactory.java @@ -0,0 +1,35 @@ +/* + * POSEIDON: an agent-based model of fisheries + * Copyright (c) 2025 CoHESyS Lab cohesys.lab@gmail.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package uk.ac.ox.poseidon.agents.vessels.hold; + +import uk.ac.ox.poseidon.agents.vessels.Vessel; +import uk.ac.ox.poseidon.agents.vessels.VesselScopeFactory; +import uk.ac.ox.poseidon.core.Simulation; + +public class ProportionalBiomassOvercapacityDiscardingStrategyFactory + extends VesselScopeFactory { + @Override + protected ProportionalBiomassOvercapacityDiscardingStrategy newInstance( + final Simulation simulation, + final Vessel vessel + ) { + return new ProportionalBiomassOvercapacityDiscardingStrategy(); + } +} diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHold.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHold.java new file mode 100644 index 000000000..3eff2ca66 --- /dev/null +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHold.java @@ -0,0 +1,67 @@ +/* + * POSEIDON: an agent-based model of fisheries + * Copyright (c) 2025 CoHESyS Lab cohesys.lab@gmail.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package uk.ac.ox.poseidon.agents.vessels.hold; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import uk.ac.ox.poseidon.agents.vessels.hold.OvercapacityDiscardingStrategy.Result; +import uk.ac.ox.poseidon.biology.Bucket; +import uk.ac.ox.poseidon.biology.biomass.Biomass; + +@RequiredArgsConstructor +public class StandardBiomassHold implements Hold { + + private final double capacityInKg; + private final double toleranceInKg; + private final OvercapacityDiscardingStrategy overcapacityDiscardingStrategy; + @Getter + private Bucket content = Bucket.empty(); + + @Override + public Bucket addContent(final Bucket contentToAdd) { + final Bucket newContent = content.add(contentToAdd); + if (newContent.getTotalBiomass().asKg() <= capacityInKg + toleranceInKg) { + content = newContent; + return Bucket.empty(); + } else { + final Result discardingResult = + overcapacityDiscardingStrategy.discard( + contentToAdd, + content, + capacityInKg, + toleranceInKg + ); + content = discardingResult.updatedHoldContent; + return discardingResult.discarded; + } + } + + @Override + public boolean isFull() { + return content.getTotalBiomass().asKg() >= capacityInKg - toleranceInKg; + } + + @Override + public Bucket removeContent() { + final Bucket removedContent = content; + content = Bucket.empty(); + return removedContent; + } +} diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHoldFactory.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHoldFactory.java new file mode 100644 index 000000000..516c7bad2 --- /dev/null +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/StandardBiomassHoldFactory.java @@ -0,0 +1,60 @@ +/* + * POSEIDON: an agent-based model of fisheries + * Copyright (c) 2025 CoHESyS Lab cohesys.lab@gmail.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package uk.ac.ox.poseidon.agents.vessels.hold; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import uk.ac.ox.poseidon.agents.vessels.Vessel; +import uk.ac.ox.poseidon.agents.vessels.VesselScopeFactory; +import uk.ac.ox.poseidon.biology.biomass.Biomass; +import uk.ac.ox.poseidon.core.Factory; +import uk.ac.ox.poseidon.core.Simulation; + +import javax.measure.Quantity; +import javax.measure.quantity.Mass; + +import static javax.measure.MetricPrefix.KILO; +import static tech.units.indriya.unit.Units.GRAM; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class StandardBiomassHoldFactory extends VesselScopeFactory { + + private Factory> capacity; + private Factory> tolerance; + private VesselScopeFactory> + overcapacityDiscardingStrategy; + + @Override + protected StandardBiomassHold newInstance( + final Simulation simulation, + final Vessel vessel + ) { + return new StandardBiomassHold( + capacity.get(simulation).to(KILO(GRAM)).getValue().doubleValue(), + tolerance.get(simulation).to(KILO(GRAM)).getValue().doubleValue(), + overcapacityDiscardingStrategy.get(simulation, vessel) + ); + } +} diff --git a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/VoidHold.java b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/VoidHold.java index 2b5199d74..1c9ecc570 100644 --- a/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/VoidHold.java +++ b/agents/src/main/java/uk/ac/ox/poseidon/agents/vessels/hold/VoidHold.java @@ -54,6 +54,16 @@ public Bucket getContent() { return Bucket.empty(); } + /** + * A void hold is never full. There is always more room in the void. + * + * @return false + */ + @Override + public boolean isFull() { + return false; + } + /** * Removes all content from the hold and returns it. In the context of a {@code VoidHold}, no * content is actually stored, so this method will always return an empty bucket. diff --git a/agents/src/test/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyTest.java b/agents/src/test/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyTest.java new file mode 100644 index 000000000..d0c17bf11 --- /dev/null +++ b/agents/src/test/java/uk/ac/ox/poseidon/agents/vessels/hold/ProportionalBiomassOvercapacityDiscardingStrategyTest.java @@ -0,0 +1,161 @@ +/* + * POSEIDON: an agent-based model of fisheries + * Copyright (c) 2025 CoHESyS Lab cohesys.lab@gmail.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package uk.ac.ox.poseidon.agents.vessels.hold; + +import org.junit.jupiter.api.Test; +import uk.ac.ox.poseidon.agents.vessels.hold.OvercapacityDiscardingStrategy.Result; +import uk.ac.ox.poseidon.biology.Bucket; +import uk.ac.ox.poseidon.biology.biomass.Biomass; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static uk.ac.ox.poseidon.biology.species.DummySpecies.A; +import static uk.ac.ox.poseidon.biology.species.DummySpecies.B; + +class ProportionalBiomassOvercapacityDiscardingStrategyTest { + + @Test + void discard_AllContentFitsWithinCapacity_NoDiscardingDone() { + // Arrange + final ProportionalBiomassOvercapacityDiscardingStrategy strategy = + new ProportionalBiomassOvercapacityDiscardingStrategy(); + + final Bucket contentToAdd = Bucket.of(A, Biomass.ofKg(20.0)); + final Bucket currentHoldContent = Bucket.of(B, Biomass.ofKg(30.0)); + + final double capacityInKg = 100.0; + final double toleranceInKg = 0.1; + + // Act + final Result result = strategy.discard( + contentToAdd, + currentHoldContent, + capacityInKg, + toleranceInKg + ); + + // Assert + assertTrue(result.discarded.isEmpty(), "No biomass should be discarded."); + assertEquals(50.0, result.updatedHoldContent.getTotalBiomass().asKg(), 0.001); + } + + @Test + void discard_ContentExceedsCapacity_DiscardProportionally() { + // Arrange + final ProportionalBiomassOvercapacityDiscardingStrategy strategy = + new ProportionalBiomassOvercapacityDiscardingStrategy(); + + final Bucket contentToAdd = Bucket.of(A, Biomass.ofKg(40.0)); + final Bucket currentHoldContent = Bucket.of(B, Biomass.ofKg(30.0)); + final double capacityInKg = 50.0; + final double toleranceInKg = 0.1; + + // Act + final Result result = strategy.discard( + contentToAdd, + currentHoldContent, + capacityInKg, + toleranceInKg + ); + + // Assert + assertEquals( + 20.0, + result.discarded.getTotalBiomass().asKg(), + 0.001, + "20kg should be discarded." + ); + assertEquals( + 50.0, + result.updatedHoldContent.getTotalBiomass().asKg(), + 0.001, + "Hold content should be capped to the capacity." + ); + } + + @Test + void discard_AllCapacityFull_AllContentDiscarded() { + // Arrange + final ProportionalBiomassOvercapacityDiscardingStrategy strategy = + new ProportionalBiomassOvercapacityDiscardingStrategy(); + + final Bucket contentToAdd = Bucket.of(A, Biomass.ofKg(10.0)); + final Bucket currentHoldContent = Bucket.of(B, Biomass.ofKg(30.0)); + + final double capacityInKg = 30.0; + final double toleranceInKg = 0.1; + + // Act + final Result result = strategy.discard( + contentToAdd, + currentHoldContent, + capacityInKg, + toleranceInKg + ); + + // Assert + assertEquals( + 10.0, + result.discarded.getTotalBiomass().asKg(), + 0.001, + "All 10kg should be discarded." + ); + assertEquals( + 30.0, + result.updatedHoldContent.getTotalBiomass().asKg(), + 0.001, + "Hold content should be unchanged." + ); + } + + @Test + void discard_ContentExceedsCapacityBySmallAmount_RemainderDiscarded() { + // Arrange + final ProportionalBiomassOvercapacityDiscardingStrategy strategy = + new ProportionalBiomassOvercapacityDiscardingStrategy(); + + final Bucket contentToAdd = Bucket.of(A, Biomass.ofKg(25.0)); + final Bucket currentHoldContent = Bucket.of(B, Biomass.ofKg(30.0)); + final double capacityInKg = 50.0; + final double toleranceInKg = 0.1; + + // Act + final Result result = strategy.discard( + contentToAdd, + currentHoldContent, + capacityInKg, + toleranceInKg + ); + + // Assert + assertEquals( + 5.0, + result.discarded.getTotalBiomass().asKg(), + 0.001, + "5kg should be discarded." + ); + assertEquals( + 50.0, + result.updatedHoldContent.getTotalBiomass().asKg(), + 0.001, + "Hold content should be capped to the capacity." + ); + } +} diff --git a/biology/src/main/java/uk/ac/ox/poseidon/biology/Bucket.java b/biology/src/main/java/uk/ac/ox/poseidon/biology/Bucket.java index c37c1aaa2..bbac36991 100644 --- a/biology/src/main/java/uk/ac/ox/poseidon/biology/Bucket.java +++ b/biology/src/main/java/uk/ac/ox/poseidon/biology/Bucket.java @@ -45,6 +45,13 @@ static > Bucket copyOf(final Bucket other) { return Bucket.from(other.getMap()); } + static > Bucket of( + final Species species, + final C content + ) { + return Bucket.newBuilder().put(species, content).build(); + } + static > Bucket from( final Map map ) { @@ -162,7 +169,7 @@ public Builder subtract( final Species species, final C content ) { - map.merge(species, content, Content::add); + map.merge(species, content, Content::subtract); return this; } diff --git a/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/Biomass.java b/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/Biomass.java index 5eccb20f3..99ad50d98 100644 --- a/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/Biomass.java +++ b/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/Biomass.java @@ -35,6 +35,8 @@ @Getter public class Biomass implements Content { + // TODO: should I embrace the kilograms and provide a asQuantity method instead? + private Quantity quantity; public Biomass( @@ -56,6 +58,14 @@ public Biomass subtract(final Biomass content) { return new Biomass(quantity.subtract(content.quantity)); } + public Biomass multiply(final double value) { + return new Biomass(quantity.multiply(value)); + } + + public Biomass divide(final double value) { + return new Biomass(quantity.divide(value)); + } + public boolean isEmpty() { return quantity.isEquivalentTo(Quantities.getQuantity(0, KILO(GRAM))); } @@ -68,4 +78,6 @@ public Biomass asBiomass() { public double asKg() { return quantity.to(KILO(GRAM)).getValue().doubleValue(); } + + public String toString() {return "Biomass(" + this.getQuantity() + ")";} } diff --git a/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/UniformCarryingCapacityGridFactory.java b/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/UniformCarryingCapacityGridFactory.java index e5f29aa9e..f3ada6824 100644 --- a/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/UniformCarryingCapacityGridFactory.java +++ b/biology/src/main/java/uk/ac/ox/poseidon/biology/biomass/UniformCarryingCapacityGridFactory.java @@ -29,7 +29,8 @@ import javax.measure.Quantity; import javax.measure.quantity.Mass; -import static si.uom.NonSI.TONNE; +import static javax.measure.MetricPrefix.KILO; +import static tech.units.indriya.unit.Units.GRAM; @Getter @Setter @@ -46,16 +47,16 @@ protected CarryingCapacityGrid newInstance(final Simulation simulation) { final BathymetricGrid bathymetricGrid = this.bathymetricGrid.get(simulation); final GridExtent gridExtent = bathymetricGrid.getGridExtent(); final double[][] array = gridExtent.makeDoubleArray(); - final double carryingCapacityInTonnes = + final double carryingCapacityInKg = carryingCapacity .get(simulation) - .to(TONNE) + .to(KILO(GRAM)) .getValue() .doubleValue(); bathymetricGrid.getAllCells().forEach(cell -> array[cell.x][cell.y] = bathymetricGrid.isWater(cell) - ? carryingCapacityInTonnes + ? carryingCapacityInKg : Double.NaN ); return new CarryingCapacityGrid(gridExtent, array); diff --git a/core/src/main/java/uk/ac/ox/poseidon/core/quantities/AbstractQuantityFactory.java b/core/src/main/java/uk/ac/ox/poseidon/core/quantities/AbstractQuantityFactory.java index 3615b5f8d..8cb8e1040 100644 --- a/core/src/main/java/uk/ac/ox/poseidon/core/quantities/AbstractQuantityFactory.java +++ b/core/src/main/java/uk/ac/ox/poseidon/core/quantities/AbstractQuantityFactory.java @@ -23,6 +23,7 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; +import si.uom.NonSI; import tech.units.indriya.format.SimpleQuantityFormat; import tech.units.indriya.format.SimpleUnitFormat; import tech.units.indriya.quantity.Quantities; @@ -39,6 +40,13 @@ public abstract class AbstractQuantityFactory> extends GlobalScopeFactory> { + static { + // We need to trigger static initialization of the NonSI class + // in order for non-SI unit string formats to be registered + // noinspection ResultOfMethodCallIgnored + NonSI.getInstance(); + } + private final Class type; private double value; private String unitString; diff --git a/examples/src/main/java/uk/ac/ox/poseidon/examples/BasicScenario.java b/examples/src/main/java/uk/ac/ox/poseidon/examples/BasicScenario.java index e140eab03..f914de11a 100644 --- a/examples/src/main/java/uk/ac/ox/poseidon/examples/BasicScenario.java +++ b/examples/src/main/java/uk/ac/ox/poseidon/examples/BasicScenario.java @@ -51,7 +51,8 @@ import uk.ac.ox.poseidon.agents.vessels.VesselScopeFactoryDecorator; import uk.ac.ox.poseidon.agents.vessels.gears.FixedBiomassProportionGearFactory; import uk.ac.ox.poseidon.agents.vessels.hold.Hold; -import uk.ac.ox.poseidon.agents.vessels.hold.InfiniteHoldFactory; +import uk.ac.ox.poseidon.agents.vessels.hold.ProportionalBiomassOvercapacityDiscardingStrategyFactory; +import uk.ac.ox.poseidon.agents.vessels.hold.StandardBiomassHoldFactory; import uk.ac.ox.poseidon.biology.biomass.*; import uk.ac.ox.poseidon.biology.species.Species; import uk.ac.ox.poseidon.biology.species.SpeciesFactory; @@ -89,7 +90,6 @@ import java.util.List; import java.util.function.Predicate; -import static si.uom.NonSI.TONNE; import static uk.ac.ox.poseidon.core.suppliers.ConstantDurationSuppliers.ONE_DAY_DURATION_SUPPLIER; import static uk.ac.ox.poseidon.core.suppliers.ConstantDurationSuppliers.ONE_HOUR_DURATION_SUPPLIER; import static uk.ac.ox.poseidon.core.time.PeriodFactory.DAILY; @@ -103,7 +103,7 @@ public class BasicScenario extends Scenario { private static final double PERCENTAGE_LIMIT_ON_DAILY_MOVEMENT = 0.1; private static final double LOGISTIC_GROWTH_RATE = 0.001; private static final int GRID_SIZE = 51; - private static final int CARRYING_CAPACITY_IN_TONNES = 5; + private static final String CARRYING_CAPACITY = "5 t"; private static final double LEARNING_ALPHA = 1; private static final double READINESS_PROBABILITY = 0.9; private static final int NUMBER_OF_PORTS = 1; @@ -112,6 +112,7 @@ public class BasicScenario extends Scenario { private static final int MEAN_EXPLORATION_RADIUS = 1; private static final double CATCH_PROPORTION = 0.1; private static final int VESSEL_SPEED = 15; + private static final String VESSEL_HOLD_CAPACITY = "1 t"; private Factory>> optionValuesRegister = new RegisterFactory<>(); @@ -185,7 +186,7 @@ public class BasicScenario extends Scenario { private Factory carryingCapacityGrid = new UniformCarryingCapacityGridFactory( bathymetricGrid, - new MassFactory(CARRYING_CAPACITY_IN_TONNES, TONNE) + new MassFactory(CARRYING_CAPACITY) ); private Factory biomassAllocator = new FullBiomassAllocatorFactory(carryingCapacityGrid); @@ -243,7 +244,11 @@ public class BasicScenario extends Scenario { ), 0 ); - private VesselScopeFactory> hold = new InfiniteHoldFactory<>(); + private VesselScopeFactory> hold = new StandardBiomassHoldFactory( + new MassFactory(VESSEL_HOLD_CAPACITY), + new MassFactory("1 kg"), + new ProportionalBiomassOvercapacityDiscardingStrategyFactory() + ); private VesselScopeFactory> optionValues = new RegisteringFactory<>( optionValuesRegister,