diff --git a/.classpath b/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..9aa3736ab285bbaeb493abcb3491869283d4e428 --- /dev/null +++ b/.classpath @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="lib" path="C:/Users/guillaume.garbay/workspace/Lib/SimAquaLife/simaqualife-2.0.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/.project b/.project new file mode 100644 index 0000000000000000000000000000000000000000..9dd8a958373526383d3debf4d1b4b0fbf2573d60 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>PikeLake</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000000000000000000000000000000000..e532d9854f267cc2d68d89135fd93258c7025e3b --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//data/input=ISO-8859-1 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..bb35fa0a87b032ee9d0b128004c1edbd464f07bf --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/data/input/fish.xml b/data/input/fish.xml new file mode 100644 index 0000000000000000000000000000000000000000..1be074a790a70b4e5b6d452b1bce30048c973c13 --- /dev/null +++ b/data/input/fish.xml @@ -0,0 +1,31 @@ +<list> + <pikelake.pikes.PikesGroup> + <weightAtAgeThreshold>5.0</weightAtAgeThreshold> + <monthOfBirth>6</monthOfBirth> + <processes> + <processesAtBegin> + <pikelake.pikes.PikesPopulateProcess> + <initialNumberOfPikes>5</initialNumberOfPikes> + </pikelake.pikes.PikesPopulateProcess> + </processesAtBegin> + <processesEachStep> + <pikelake.pikes.PikeMovement/> + <pikelake.pikes.PikeHuntProcess> + <satiety>0.5</satiety> + </pikelake.pikes.PikeHuntProcess> + <pikelake.pikes.PikeGrowthProcess> + <convertionFactor>0.25</convertionFactor> + <slimRate>0.9</slimRate> + </pikelake.pikes.PikeGrowthProcess> + <pikelake.pikes.PikeMortalityProcess/> + <pikelake.pikes.PikeReproductionProcess> + <ageAtFirstReproduction>5</ageAtFirstReproduction> + <pikeFertility>1.3</pikeFertility> + </pikelake.pikes.PikeReproductionProcess> + <pikelake.pikes.PikeObservationProcess/> + <fr.cemagref.simaqualife.kernel.processes.FireAquaNismsChangesToObservers/> + </processesEachStep> + </processes> + <useCemetery>false</useCemetery> + </pikelake.pikes.PikesGroup> +</list> \ No newline at end of file diff --git a/data/input/fishLight.xml b/data/input/fishLight.xml new file mode 100644 index 0000000000000000000000000000000000000000..0ce26be0296d14abb33456974c3c8d773cf52744 --- /dev/null +++ b/data/input/fishLight.xml @@ -0,0 +1,26 @@ +<list> + <pikelake.pikes.PikesGroup> + <weightAtAgeThreshold>5.0</weightAtAgeThreshold> + <monthOfBirth>6</monthOfBirth> + <processes> + <processesAtBegin> + <pikelake.pikes.PikesPopulateProcess> + <initialNumberOfPikes>1</initialNumberOfPikes> + </pikelake.pikes.PikesPopulateProcess> + </processesAtBegin> + <processesEachStep> + <pikelake.pikes.PikeMovement/> + <pikelake.pikes.PikeHuntProcess> + <satiety>0.5</satiety> + </pikelake.pikes.PikeHuntProcess> + <pikelake.pikes.PikeGrowthProcess> + <convertionFactor>0.25</convertionFactor> + <slimRate>0.9</slimRate> + </pikelake.pikes.PikeGrowthProcess> + <pikelake.pikes.PikeObservationProcess/> + <fr.cemagref.simaqualife.kernel.processes.FireAquaNismsChangesToObservers/> + </processesEachStep> + </processes> + <useCemetery>false</useCemetery> + </pikelake.pikes.PikesGroup> +</list> \ No newline at end of file diff --git a/data/input/grid.xml b/data/input/grid.xml new file mode 100644 index 0000000000000000000000000000000000000000..5ca1d3dd6b9c246cb91e6cf161a3d500bedf00ef --- /dev/null +++ b/data/input/grid.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<pikelake.Grid> + <torusType>BOTH</torusType> + <neighborsType>NEIGHBORHOOD_VON_NEUMANN</neighborsType> + <preyCarryingCapacity>50</preyCarryingCapacity> + <gridWidth>10</gridWidth> + <gridHeight>10</gridHeight> + <habitatValue0>0.25</habitatValue0> + <habitatValue1>0.5</habitatValue1> + <habitatValue2>1</habitatValue2> +</pikelake.Grid> \ No newline at end of file diff --git a/data/input/observersBatch.xml b/data/input/observersBatch.xml new file mode 100644 index 0000000000000000000000000000000000000000..54ed95bbc90303ef2bb8bfae08bc284e4c9006f9 --- /dev/null +++ b/data/input/observersBatch.xml @@ -0,0 +1,14 @@ +<hashtable> + <entry> + <java-class>pikeprey.pikes.PikesGroup</java-class> + <fr.cemagref.observation.kernel.ObservablesHandler> + <observers> + <fr.cemagref.observation.observers.CSVObserver> + <separator>;</separator> + <sysout>false</sysout> + <outputFile>data/pikes.txt</outputFile> + </fr.cemagref.observation.observers.CSVObserver> + </observers> + </fr.cemagref.observation.kernel.ObservablesHandler> + </entry> +</hashtable> diff --git a/data/input/observersCharts.xml b/data/input/observersCharts.xml new file mode 100644 index 0000000000000000000000000000000000000000..d8381767312783b51d74bf15d6f84054e15df677 --- /dev/null +++ b/data/input/observersCharts.xml @@ -0,0 +1,28 @@ +<hashtable> + <entry> + <java-class>pikelake.pikes.PikesGroup</java-class> + <fr.cemagref.observation.kernel.ObservablesHandler> + <observers> + <fr.cemagref.observation.observers.jfreechart.TemporalSerieChart> + <graphType>LINE</graphType> + <title>Observation of pikes biomass</title> + <xAxisLabel>Time (month)</xAxisLabel> + <yAxisLabel>pikes biomass</yAxisLabel> + </fr.cemagref.observation.observers.jfreechart.TemporalSerieChart> + </observers> + </fr.cemagref.observation.kernel.ObservablesHandler> + </entry> + <entry> + <java-class>pikelake.pikes.Pike</java-class> + <fr.cemagref.observation.kernel.ObservablesHandler> + <observers> + <fr.cemagref.observation.observers.jfreechart.TemporalSerieChart> + <graphType>LINE</graphType> + <title>Observation of pikes</title> + <xAxisLabel>Time (month)</xAxisLabel> + <yAxisLabel></yAxisLabel> + </fr.cemagref.observation.observers.jfreechart.TemporalSerieChart> + </observers> + </fr.cemagref.observation.kernel.ObservablesHandler> + </entry> +</hashtable> diff --git a/src/main/java/pikelake/Cell.java b/src/main/java/pikelake/Cell.java new file mode 100644 index 0000000000000000000000000000000000000000..95fbff0a7a00930f859862c5be227302f38ec255 --- /dev/null +++ b/src/main/java/pikelake/Cell.java @@ -0,0 +1,78 @@ +package pikelake; + +import fr.cemagref.simaqualife.extensions.spatial2D.Grid2D; +import fr.cemagref.simaqualife.extensions.spatial2D.IndexedCell; +import fr.cemagref.simaqualife.pilot.Pilot; + +import java.util.ArrayList; +import java.util.List; + +import pikelake.pikes.Pike; +// import predatorprey.preys.Prey; ///////////////////////////////////////////////////////////////// + +public class Cell extends IndexedCell { + + /** + * <code>preyCarryingCapacity</code> number of preys that this place can + * support + */ +// private int preyCarryingCapacity; ///////////////////////////////////////////////////////////////// + + /** + * <code>habitatQuality</code> The quality of this place (pike point of + * view). A high value means that preys are vulnerable for the pikes + */ + private double habitatQuality; + + /** + * <code>preys</code> The list of preys in this place + */ +// private transient List<Prey> preys; ///////////////////////////////////////////////////////////////// + + /** + * <code>pikes</code> The list of pikes in this place + */ + private transient List<Pike> pikes; + + public Cell(int index, double habitatQuality) { // , int preyCarryingCapacity) { ////////////////////// + super(index); + this.habitatQuality = habitatQuality; +// this.preyCarryingCapacity = preyCarryingCapacity; ///////////////////////////////////////////////////////////////// + +// preys = new ArrayList<Prey>(); ///////////////////////////////////////////////////////////////// + pikes = new ArrayList<Pike>(); + } + +// public List<Prey> getPreys() { ///////////////////////////////////////////////////////////////// +// return preys; ///////////////////////////////////////////////////////////////// +// } ///////////////////////////////////////////////////////////////// + + public List<Pike> getPikes() { + return pikes; + } + +// public boolean addPrey(Prey prey) { ///////////////////////////////////////////////////////////////// +// return preys.add(prey); ///////////////////////////////////////////////////////////////// +// } ///////////////////////////////////////////////////////////////// + +// public boolean removePrey(Prey prey) { ///////////////////////////////////////////////////////////////// +// return preys.remove(prey); ///////////////////////////////////////////////////////////////// +// } ///////////////////////////////////////////////////////////////// + + public boolean addPike(Pike pike) { + return pikes.add(pike); + } + + public boolean removePike(Pike pike) { + return pikes.remove(pike); + } + + public double getHabitatQuality() { + return habitatQuality; + } + +// public int getPreyCarryingCapacity() { ///////////////////////////////////////////////////////////////// +// return preyCarryingCapacity; ///////////////////////////////////////////////////////////////// +// } ///////////////////////////////////////////////////////////////// + +} diff --git a/src/main/java/pikelake/Grid.java b/src/main/java/pikelake/Grid.java new file mode 100644 index 0000000000000000000000000000000000000000..82bb1289b47b5f1f6a7a2cb7cfdda435a92dc9e4 --- /dev/null +++ b/src/main/java/pikelake/Grid.java @@ -0,0 +1,81 @@ +package pikelake; + +import fr.cemagref.simaqualife.extensions.spatial2D.Grid2D; +import fr.cemagref.simaqualife.extensions.spatial2D.Grid2D.NeighborsType; +import fr.cemagref.simaqualife.kernel.AquaNismsGroup; +import fr.cemagref.simaqualife.kernel.util.TransientParameters.InitTransientParameters; +import fr.cemagref.simaqualife.pilot.Pilot; +import pikelake.pikes.Pike; +//import predatorprey.preys.Prey; +import umontreal.iro.lecuyer.probdist.UniformDist; +import umontreal.iro.lecuyer.randvar.UniformGen; + +public class Grid extends Grid2D<Cell, Individual> { + + public Grid(int gridWidth, int gridHeight, NeighborsType neighborsType) { + super(gridWidth, gridHeight, neighborsType); + // TODO Auto-generated constructor stub + } + + /** + * <code>preyCarryingCapacity</code> number of preys that a cell can support + */ +// private int preyCarryingCapacity; + private double habitatValue0 = .25; + private double habitatValue1 = .5; + private double habitatValue2 = 1; + + transient private UniformGen uniformGen; + transient private double[] habitatValues; + + @InitTransientParameters + public void initTransientParameters(Pilot pilot) { + + this.pos = neighborsType.getPos(); + + habitatValues = new double[3]; + habitatValues[0] = habitatValue0; + habitatValues[1] = habitatValue1; + habitatValues[2] = habitatValue2; + + UniformGen uniformGen = new UniformGen(pilot.getRandomStream(), new UniformDist(0, habitatValues.length - 1)); + + grid = new Cell[gridWidth * gridHeight]; + for (int i = 0; i < grid.length; i++) { + double hab = habitatValues[(int) Math.round(uniformGen.nextDouble())]; + grid[i] = new Cell(i, hab); // , preyCarryingCapacity); ///////////////////////////////////////////////////////////////// + } + } + + @Override + public void addAquaNism(Individual ind, AquaNismsGroup group) { + super.addAquaNism(ind, group); +// if (ind instanceof Prey) { ///////////////////////////////////////////////////////////////// +// ind.getPosition().addPrey((Prey) ind); ///////////////////////////////////////////////////////////////// +// } else { ///////////////////////////////////////////////////////////////// + ind.getPosition().addPike((Pike) ind); +// } ///////////////////////////////////////////////////////////////// + } + + @Override + public void moveAquaNism(Individual ind, AquaNismsGroup group, Cell dest) { + super.moveAquaNism(ind, group, dest); + this.removeAquaNism(ind, group); +// if (ind instanceof Prey) { ///////////////////////////////////////////////////////////////// +// dest.addPrey((Prey) ind); ///////////////////////////////////////////////////////////////// +// } else { ///////////////////////////////////////////////////////////////// + dest.addPike((Pike) ind); +// } ///////////////////////////////////////////////////////////////// + } + + @Override + public void removeAquaNism(Individual ind, AquaNismsGroup group) { + super.removeAquaNism(ind, group); +// if (ind instanceof Prey) { ///////////////////////////////////////////////////////////////// +// ind.getPosition().removePrey((Prey) ind); ///////////////////////////////////////////////////////////////// +// } else { ///////////////////////////////////////////////////////////////// + ind.getPosition().removePike((Pike) ind); +// } ///////////////////////////////////////////////////////////////// + } + +} diff --git a/src/main/java/pikelake/GridObserver.java b/src/main/java/pikelake/GridObserver.java new file mode 100644 index 0000000000000000000000000000000000000000..ab6b9cbec43ea674043b1140761f577e8fdfc25e --- /dev/null +++ b/src/main/java/pikelake/GridObserver.java @@ -0,0 +1,204 @@ +package pikelake; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.awt.geom.Rectangle2D; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +import fr.cemagref.observation.gui.Configurable; +import fr.cemagref.observation.gui.Drawable; +import fr.cemagref.observation.kernel.ObservablesHandler; +import fr.cemagref.observation.kernel.ObserverListener; +import fr.cemagref.ohoui.annotations.Description; +import fr.cemagref.ohoui.annotations.NoRecursive; +import fr.cemagref.ohoui.filters.NoTransientField; +import fr.cemagref.ohoui.swing.OhOUI; +import fr.cemagref.ohoui.swing.OhOUIDialog; +import fr.cemagref.simaqualife.kernel.util.TransientParameters; +import fr.cemagref.simaqualife.pilot.Pilot; + +@SuppressWarnings("serial") +@NoRecursive +public class GridObserver extends ObserverListener implements Configurable, Drawable, MouseMotionListener { + + private transient JComponent display; + private transient JLabel label; + private transient Grid grid; + + private String title; + + private Color envColor = Color.GREEN; + private Color preyColor = Color.BLUE; + private Color pikeColor = Color.RED; + @Description (name="Background color",tooltip="Background color") + private Color bgColor = Color.WHITE; + + private transient int displayWidthBak,displayHeightBak; + private transient double cellSizeX, cellSizeY; + private transient int[] cellsAlpha; + + public String getTitle() { + return title; + } + + public JComponent getDisplay() { + return display; + } + + public void valueChanged(ObservablesHandler clObservable, Object instance, long t) { + display.repaint(); + } + + @TransientParameters.InitTransientParameters + public void init(Pilot pilot) { + // init display component + display = new JPanel(new BorderLayout()); + DisplayComponent displayComponent = new DisplayComponent(); + displayComponent.addMouseMotionListener(this); + displayComponent.setVisible(true); + displayComponent.setDoubleBuffered(true); + label = new JLabel(""); + display.add(displayComponent,BorderLayout.CENTER); + display.add(label,BorderLayout.PAGE_START); + grid = (Grid)pilot.getAquaticWorld().getEnvironment(); + + // init display variables + displayWidthBak = 0; + displayHeightBak = 0; + // compute HabitatQuality colors + double cellsHabitatQualityMin = 0; + double cellsHabitatQualityMax = 0; + cellsAlpha = new int[grid.getCells().length]; + if (grid.getCells().length > 0) { + cellsHabitatQualityMin = grid.getCells()[0].getHabitatQuality(); + cellsHabitatQualityMax = grid.getCells()[0].getHabitatQuality(); + for (int i = 1; i < grid.getCells().length; i++) { + if (grid.getCells()[i].getHabitatQuality() < cellsHabitatQualityMin) + cellsHabitatQualityMin = grid.getCells()[i].getHabitatQuality(); + else if (grid.getCells()[i].getHabitatQuality() > cellsHabitatQualityMax) + cellsHabitatQualityMax = grid.getCells()[i].getHabitatQuality(); + } + } + if (Double.compare(cellsHabitatQualityMax,cellsHabitatQualityMin) == 0) { + for (int i = 0; i < grid.getCells().length; i++) { + cellsAlpha[i] = 255; + } + } else { + for (int i = 0; i < grid.getCells().length; i++) { + cellsAlpha[i] = (int)(155 + 100*(grid.getCells()[i].getHabitatQuality() - cellsHabitatQualityMin)/(cellsHabitatQualityMax - cellsHabitatQualityMin)); + } + } + // show the result + display.repaint(); + } + + public void disable() { + display.setVisible(false); + } + + public static interface AsShapeConvertible { + public Shape getShape(); + } + + public void configure() { + OhOUIDialog dialog = OhOUI.getDialog(null,this,new NoTransientField()); + dialog.setSize(new Dimension(500, 600)); + dialog.setVisible(true); + display.repaint(); + } + + @Override + public void addObservable(ObservablesHandler classObservable) { + // nothing to do + } + + @Override + public void init() { + // nothing to do + } + + @Override + public void close() { + // nothing to do + } + + private class DisplayComponent extends JComponent { + + @Override + protected synchronized void paintComponent(Graphics g) { + super.paintComponents(g); + Graphics2D g2d = (Graphics2D)g; + // determine if generalPath must be rescaled + if ( (this.getWidth() != displayWidthBak) || (this.getHeight() != displayHeightBak) ) { + // backup for comparaison in the next loop + displayWidthBak = this.getWidth(); + displayHeightBak = this.getHeight(); + cellSizeX = displayWidthBak/grid.getGridWidth(); + cellSizeY = displayHeightBak/grid.getGridHeight(); + } + // Draw Background + g.setColor(bgColor); + g2d.setStroke(new BasicStroke(3)); + g.fillRect(0, 0, getWidth(), getHeight()); + Rectangle2D.Double cellRect = null; + Rectangle2D.Double pikeRect = null; + double preyDiameterX, preyDiameterY, pikeWidth, pikeHeight; + // draw each cell + for (int i = 0; i < grid.getCells().length; i++) { + // the bounds of a cell + cellRect = new Rectangle2D.Double((int)cellSizeX*(i%grid.getGridWidth()), (int)cellSizeY*(i/grid.getGridHeight()), (int)cellSizeX, (int)cellSizeY); + // filling the cell with a color corresponding to the habitat level + g.setColor(new Color(envColor.getRed(),envColor.getGreen(),envColor.getBlue(),cellsAlpha[i])); + g2d.fill(cellRect); + // drawing preys + if (grid.getCells()[i].getPreys().size() > 0) { + g.setColor(preyColor); + preyDiameterX = cellRect.width*(double)grid.getCells()[i].getPreys().size()/grid.getCells()[i].getPreyCarryingCapacity(); + preyDiameterY = cellRect.height*(double)grid.getCells()[i].getPreys().size()/grid.getCells()[i].getPreyCarryingCapacity(); + g.fillOval((int)(cellRect.x + (cellRect.width - preyDiameterX)/2), (int)(cellRect.y + (cellRect.height - preyDiameterY)/2), (int)preyDiameterX, (int)preyDiameterY); + // represention as pie ... not very pretty + /*g2d.fill(new Arc2D.Double(cellRect,90,-360*((double)grid.getCells()[i].getPreys().size()/grid.getCells()[i].getPreyCarryingCapacity()),Arc2D.PIE)); + g2d.draw(new Arc2D.Double(cellRect,90,360,Arc2D.OPEN));*/ + } + // drawing pikes presence + if (grid.getCells()[i].getPikes().size() > 0) { + g.setColor(pikeColor); + pikeWidth = cellRect.width / 3; + pikeHeight = cellRect.height / 3; + pikeRect = new Rectangle2D.Double(cellRect.x + (cellRect.width - pikeWidth)/2, cellRect.y + (cellRect.height - pikeHeight)/2, pikeWidth, pikeHeight); + g2d.draw(pikeRect); + g2d.drawString(""+grid.getCells()[i].getPikes().size(), (float)(cellRect.x + cellRect.width/2 - 5), (float)pikeRect.y+(float)pikeRect.height-1); + } + } + } + } + + public void mouseDragged(MouseEvent e) {} + + public void mouseMoved(MouseEvent e) { + int y = (int)(e.getY()/cellSizeY); + int x = (int)(e.getX()/cellSizeX); + Cell cell = grid.getCells()[grid.getGridWidth()*Math.min(y,grid.getGridHeight()-1) + Math.min(x,grid.getGridWidth()-1)]; + label.setText("( "+x+" , "+y+" ) : habitat value = "+cell.getHabitatQuality()+" / "+cell.getPreys().size() + " preys ( max = "+cell.getPreyCarryingCapacity()+") and " + cell.getPikes().size()+ " pikes."); + } + + public static void main (String [] args){ + System.out.println((new XStream(new DomDriver())).toXML(new GridObserver())); + } + + + +} diff --git a/src/main/java/pikelake/Individual.java b/src/main/java/pikelake/Individual.java new file mode 100644 index 0000000000000000000000000000000000000000..693ce30b53a2794caf148c18cf5408474a9675c5 --- /dev/null +++ b/src/main/java/pikelake/Individual.java @@ -0,0 +1,51 @@ +package pikelake; + +import fr.cemagref.observation.kernel.Observable; +import fr.cemagref.simaqualife.kernel.AquaNism; +import fr.cemagref.simaqualife.pilot.Pilot; + +public abstract class Individual extends AquaNism<Cell,Grid> implements Comparable<Individual> { + + /** + * <code>age</code> age of the individual in months + */ + protected int age; + + /** + * <code>weight</code> weight of the individual in grams + */ + @Observable(description = "weight (g)") + protected double weight; + + public Individual(Pilot pilot, Cell position) { + super(pilot, position); + this.age = 0; + } + + public Individual(Pilot pilot, Cell position, double weight) { + this(pilot, position); + this.weight = weight; + } + + public final double getWeight() { + return weight; + } + + public final void setWeight(double weight) { + this.weight = weight; + } + + public final int getAge() { + return age; + } + + public final void incAge() { + age++; + } + + public int compareTo (Individual ind){ + return (int) Math.signum(this.weight - ind.weight); + } + + +} diff --git a/src/main/java/pikelake/pikes/Pike.java b/src/main/java/pikelake/pikes/Pike.java new file mode 100644 index 0000000000000000000000000000000000000000..2a787f125b2a033ef9d69eb660b655fe3c15c1d6 --- /dev/null +++ b/src/main/java/pikelake/pikes/Pike.java @@ -0,0 +1,45 @@ +package pikelake.pikes; + +import fr.cemagref.simaqualife.pilot.Pilot; +import Pike.Cell; +import Pike.Individual; + +public class Pike extends Individual { + + private double ingestedFood=0.; + + public Pike(Pilot pilot, Cell cell) { + //TODO fix weight according to the weightAtAgeThreshold + // Default value of weight at birth + this(pilot, cell, 0, 10.); + } + + public Pike(Pilot pilot, Cell cell, int age, double weight) { + super(pilot, cell); + this.age =age; + this.weight = weight; + } + + + public double getIngestedFood() { + return ingestedFood; + } + + public void setIngestedFood(double ingestedFood) { + this.ingestedFood = ingestedFood; + } + public void addIngestedFood(double ingestedFood) { + this.ingestedFood += ingestedFood; + } + + public double getSuitabilityForPike(Cell cell){ + if (cell.getPikes().size()>1) + return 0.; // at least an other pike in the cell + else + return 1.; ///////////////////////////////////////////////////////// + //return((double) cell.getPreys().size()) * cell.getHabitatQuality(); // number of preys accessible + } + + +} + diff --git a/src/main/java/pikelake/pikes/PikeGrowthProcess.java b/src/main/java/pikelake/pikes/PikeGrowthProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..992d1c51d1ecee87aec29b7f7cda07e28a04377d --- /dev/null +++ b/src/main/java/pikelake/pikes/PikeGrowthProcess.java @@ -0,0 +1,25 @@ +package pikelake.pikes; + +import fr.cemagref.simaqualife.kernel.AquaNismsGroup; +import fr.cemagref.simaqualife.kernel.processes.LoopAquaNismsGroupProcess; + +public class PikeGrowthProcess extends LoopAquaNismsGroupProcess<Pike,AquaNismsGroup<Pike,?>> { + + /** + * <code>convertionFactor</code> proportion of the ingested food transformed into pike weight + */ + private double convertionFactor = 0.25; + private double slimRate = 0.90; + + @Override + protected void doProcess(Pike pike, AquaNismsGroup<Pike, ?> group) { + pike.incAge(); + //System.out.print(" "+ (double) pike.getAge()/12. +"y "+pike.getWeight()+ " " ); + pike.setWeight( pike.getWeight() * slimRate + pike.getIngestedFood()* convertionFactor); + //System.out.print(pike.getIngestedFood() +" " + pike.getWeight()); + //double ratio = 12* pike.getWeight()/(pike.getAge()+12); + //System.out.println("("+ ((double) Math.round(ratio*100))/100 +")"); + pike.setIngestedFood(0.0); + } + +} diff --git a/src/main/java/pikelake/pikes/PikeHuntProcess.java b/src/main/java/pikelake/pikes/PikeHuntProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..b2321e2090a1df773147c7fafc593440d6f2b112 --- /dev/null +++ b/src/main/java/pikelake/pikes/PikeHuntProcess.java @@ -0,0 +1,89 @@ +package pikelake.pikes; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import pikelake.Cell; +// import predatorprey.preys.Prey; //////////////////////////////////////////////////////////// +// import predatorprey.preys.PreysGroup; //////////////////////////////////////////////////// +import umontreal.iro.lecuyer.probdist.UniformDist; +import umontreal.iro.lecuyer.randvar.UniformGen; +import fr.cemagref.simaqualife.kernel.AquaNismsGroup; +import fr.cemagref.simaqualife.kernel.processes.LoopAquaNismsGroupProcess; +import fr.cemagref.simaqualife.kernel.util.TransientParameters.InitTransientParameters; +import fr.cemagref.simaqualife.pilot.Pilot; + +/** + * @author patrick.lambert + * + */ +public class PikeHuntProcess extends +LoopAquaNismsGroupProcess<Pike, AquaNismsGroup<Pike, ?>> { + + /** + * <code>satiety</code> ratio of the pike weigth which stops eating + * preys + */ + private double satiety = 0.10; + + transient private UniformGen uniformGen; + + @Override + protected void doProcess(Pike pike, + AquaNismsGroup<Pike, ?> group) { + Cell pikeCell = pike.getPosition(); +/* if (pikeCell.getPreys().size() > 0) { + //System.out.print(" " + pikeCell.getPreys().size() +" preys available in cell "); + //System.out.print("("+pikeCell.getX()+","+pikeCell.getY()+")"); + + // sort the preys list according to the weigth + List<Prey> sortedPreys = pikeCell.getPreys(); + Collections.sort(sortedPreys); + + double ratio = pike.getIngestedFood()/pike.getWeight(); + int idx = 0; + int idxMax = sortedPreys.size(); + int target=0; + int eaten=0; + while ((pike.getIngestedFood()/pike.getWeight() < satiety) && (idx < idxMax)) { + + // the probability for a prey to be eaten depends + // on the habitat quality in the cell + if (uniformGen.nextDouble() < pikeCell.getHabitatQuality()){ + // eat the prey + Prey eatenPrey = sortedPreys.get(target); + pike.addIngestedFood(eatenPrey.getWeight()); + + // and the prey dies + + ((PreysGroup)group.getPilot().getAquaticWorld().getAquaNismsGroupsList().get(0)).removeAquaNism(eatenPrey); + //this.interAquanism(eatenPrey); + pikeCell.removePrey(eatenPrey); + eaten ++; + } + else + target ++; + + idx++; + ratio = pike.getIngestedFood()/pike.getWeight(); + } + ratio= ((double) Math.round(100*ratio))/100; + //System.out.println(", " + eaten + " preys eaten ("+ ratio +" ), still " + pikeCell.getPreys().size()); + } */ + + } + + @InitTransientParameters + public void initTransientParameters(Pilot pilot) { + sorted = true; + comparator = new Comparator<Pike>() { + public int compare(Pike o1, Pike o2) { + return (int) Math.signum(o2.getWeight() - o1.getWeight()); + } + }; + + uniformGen = new UniformGen(pilot.getRandomStream(), new UniformDist()); + } + +} diff --git a/src/main/java/pikelake/pikes/PikeMortalityProcess.java b/src/main/java/pikelake/pikes/PikeMortalityProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..0056803300e7735680d33bf64e6412cabe94713a --- /dev/null +++ b/src/main/java/pikelake/pikes/PikeMortalityProcess.java @@ -0,0 +1,26 @@ +package pikelake.pikes; + +import java.util.ArrayList; +import java.util.List; + +import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; + + +public class PikeMortalityProcess extends AquaNismsGroupProcess<Pike, PikesGroup>{ + + public void doProcess(PikesGroup group) { + List<Pike> deadPike = new ArrayList<Pike>(); + for (Pike pike: group.getAquaNismsList()){ + double ratio = (12. * pike.getWeight() / (double) (pike.getAge()+12)); + + if (ratio < group.getWeightAtAgeThreshold()) + deadPike.add(pike); + } + // update the pikesGroup + for (Pike pike: deadPike){ + group.getAquaNismsList().remove(pike); + //ASK WHY + pike.getPosition().removePike(pike); + } + } +} diff --git a/src/main/java/pikelake/pikes/PikeMovement.java b/src/main/java/pikelake/pikes/PikeMovement.java new file mode 100644 index 0000000000000000000000000000000000000000..554f5de9bd9c7a744824d92c21dc43abc7e791eb --- /dev/null +++ b/src/main/java/pikelake/pikes/PikeMovement.java @@ -0,0 +1,60 @@ +package pikelake.pikes; + +import fr.cemagref.simaqualife.kernel.processes.LoopAquaNismsGroupProcess; +import fr.cemagref.simaqualife.kernel.util.TransientParameters.InitTransientParameters; + +import java.util.ArrayList; +import java.util.List; + +import pikelake.Cell; +import umontreal.iro.lecuyer.probdist.UniformDist; +import umontreal.iro.lecuyer.randvar.UniformGen; +import fr.cemagref.simaqualife.pilot.Pilot; + +public class PikeMovement extends LoopAquaNismsGroupProcess<Pike, PikesGroup> { + + transient private UniformGen uniformGen; + + public PikeMovement(Pilot pilot) { + uniformGen = new UniformGen(pilot.getRandomStream(), new UniformDist()); + } + @InitTransientParameters + public void initTransientParameters(Pilot pilot) { + uniformGen = new UniformGen(pilot.getRandomStream(), new UniformDist(0,1)); + } + + + @Override + protected void doProcess(Pike pike, PikesGroup group) { + + final List<Cell> surrounding = group.getEnvironment(). + getNeighbours(pike.getPosition()); + + // the first possiblity is the cell where the prey is + List<Cell> possibilities = new ArrayList<Cell>(); + possibilities.add(pike.getPosition()); + double cellSuitability = pike.getSuitabilityForPike(pike.getPosition()); + + // identify the destination possibilities in the neighbouring + // with the highest suitability + for (Cell cell : surrounding) { + double currentCellSuitability = pike.getSuitabilityForPike(cell); + if (currentCellSuitability > cellSuitability) { + cellSuitability = currentCellSuitability; + possibilities.clear(); + possibilities.add(cell); + } else if (currentCellSuitability == cellSuitability) { + possibilities.add(cell); + } + } + + // choose the destination cell + int possibilitiesNumber = possibilities.size(); + if (possibilitiesNumber == 1) { + pike.moveTo(group.getPilot(), possibilities.get(0), group); + } else { + int idx = (int) Math.floor(uniformGen.nextDouble() * (double) possibilitiesNumber); + pike.moveTo(group.getPilot(), possibilities.get(idx), group); + } + } +} diff --git a/src/main/java/pikelake/pikes/PikeObservationProcess.java b/src/main/java/pikelake/pikes/PikeObservationProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..8d20846e9ca93fa4a2b7562aecfea4304ef5593a --- /dev/null +++ b/src/main/java/pikelake/pikes/PikeObservationProcess.java @@ -0,0 +1,13 @@ +package pikelake.pikes; + +import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; + +public class PikeObservationProcess extends AquaNismsGroupProcess<Pike,PikesGroup> { + + public void doProcess(PikesGroup pikesGroup) { + pikesGroup.calculatePikesBiomass(); + pikesGroup.calculatePikesNumber(); + + } + +} diff --git a/src/main/java/pikelake/pikes/PikePlopProcess.java b/src/main/java/pikelake/pikes/PikePlopProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..9cb2eac1d8f55f2f40cd2591aba2c94fe1a6d739 --- /dev/null +++ b/src/main/java/pikelake/pikes/PikePlopProcess.java @@ -0,0 +1,18 @@ +package pikelake.pikes; + +import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; + +public class PlopProcess extends AquaNismsGroupProcess<Pike,PikesGroup> { + + private int temporisation = 3000; // in ms + + public void doProcess(PikesGroup object) { + try { + Thread.sleep(temporisation); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + +} diff --git a/src/main/java/pikelake/pikes/PikeReproductionProcess.java b/src/main/java/pikelake/pikes/PikeReproductionProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..4a2fcca23794cc2512ece7ec9cf1dfc99810c1cc --- /dev/null +++ b/src/main/java/pikelake/pikes/PikeReproductionProcess.java @@ -0,0 +1,72 @@ +/** + * + */ +package pikelake.pikes; + +import java.util.ArrayList; +import java.util.List; + +import umontreal.iro.lecuyer.probdist.PoissonDist; +import umontreal.iro.lecuyer.randvar.PoissonGen; + +import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; +import fr.cemagref.simaqualife.pilot.Pilot; + +/** + * @author patrick.lambert + * + */ +public class PikeReproductionProcess extends AquaNismsGroupProcess<Pike,PikesGroup> { + + /** + * <code>ageAtFirstReproduction</code> age at first reproduction (in year) + */ + private int ageAtFirstReproduction = 5; + + /** + * <code>pikeFertility</code> mean number of offsprings per pike + */ + private double pikeFertility = 1.1; + + transient private PoissonGen poissonGen; + + + + public void initTransientParameters(Pilot pilot) { + poissonGen = new PoissonGen(pilot.getRandomStream(), new PoissonDist(pikeFertility)); + + } + + public void doProcess(PikesGroup group) { + int offspring; + if (1+ ((group.getPilot().getCurrentTime()-1) % 12) == group.getMonthOfBirth()){ + List<Pike> offsprings = new ArrayList<Pike>(); + List<Pike> deadSpwaners = new ArrayList<Pike>(); + for (Pike pike: group.getAquaNismsList()){ + if (Math.floor((double) pike.getAge()/12.) >= ageAtFirstReproduction){ + // number of offspring + offspring = poissonGen.nextInt(); + + System.out.println(" offspring #: "+ offspring); + for (int i=0; i<offspring ;i++) + offsprings.add(new Pike(group.getPilot(), pike.getPosition())); + // die after reproduction + //if (offspring > 0) // only if reproduce + deadSpwaners.add(pike); + } + } + // update the pikesGroup + for (Pike pike: deadSpwaners){ + group.getAquaNismsList().remove(pike); + //ASK WHY + pike.getPosition().removePike(pike); + } + + for (Pike pike: offsprings) + group.addAquaNism(pike); + + } + } + + +} diff --git a/src/main/java/pikelake/pikes/PikesGroup.java b/src/main/java/pikelake/pikes/PikesGroup.java new file mode 100644 index 0000000000000000000000000000000000000000..c63276942770d5466e2881dc7f6b9599d4d58dd8 --- /dev/null +++ b/src/main/java/pikelake/pikes/PikesGroup.java @@ -0,0 +1,64 @@ +package pikelake.pikes; + +import pikelake.Grid; +import fr.cemagref.observation.kernel.Observable; +import fr.cemagref.simaqualife.kernel.AquaNismsGroup; +import fr.cemagref.simaqualife.kernel.Processes; +import fr.cemagref.simaqualife.pilot.Pilot; + + +public class PikesGroup extends AquaNismsGroup<Pike,Grid> { + + /** + * <code>weightAtAgeThreshold</code> threshold of the ratio of weight (in g) by age (in year) + */ + private double weightAtAgeThreshold = 5; + + + /** + * <code>monthOfBirth</code> month of reproduction + */ + private int monthOfBirth = 6; + + + @Observable(description = "Pikes biomass (g)") + private transient double pikesBiomass; + + @Observable(description = "Pikes number") + private transient int pikesNumber; + + + + public PikesGroup(Pilot pilot, Grid arg0, Processes arg1) { + super(pilot, arg0, arg1); + } + + public int calculatePikesNumber(){ + pikesNumber = this.getAquaNismsList().size(); + + /*int pikesNumber2=0; + for (Cell cell: this.getEnvironment().getCells()){ + pikesNumber2 += cell.getPikes().size(); + } + System.out.println(" pred: "+pikesNumber + " " + pikesNumber2);*/ + return pikesNumber; + + } + + public double calculatePikesBiomass(){ + pikesBiomass =0.; + for(Pike pike : this.getAquaNismsList()) + pikesBiomass += pike.getWeight(); + return pikesBiomass; + + } + + + public int getMonthOfBirth() { + return monthOfBirth; + } + + public double getWeightAtAgeThreshold() { + return weightAtAgeThreshold; + } +} diff --git a/src/main/java/pikelake/pikes/PikesPopulateProcess.java b/src/main/java/pikelake/pikes/PikesPopulateProcess.java new file mode 100644 index 0000000000000000000000000000000000000000..bf8bacf6190edf4e4c57a24f2de5f25f02ae66c3 --- /dev/null +++ b/src/main/java/pikelake/pikes/PikesPopulateProcess.java @@ -0,0 +1,33 @@ +package pikelake.pikes; + +import pikelake.Cell; +import umontreal.iro.lecuyer.probdist.UniformDist; +import umontreal.iro.lecuyer.randvar.UniformGen; +import fr.cemagref.simaqualife.kernel.processes.AquaNismsGroupProcess; +import fr.cemagref.simaqualife.kernel.util.TransientParameters.InitTransientParameters; +import fr.cemagref.simaqualife.pilot.Pilot; + +public class PikesPopulateProcess extends AquaNismsGroupProcess<Pike,PikesGroup> { + + private int initialNumberOfPikes =5 ; + + transient private UniformGen uniformGen; + + @InitTransientParameters + public void initTransientParameters(Pilot pilot) { + double nbCell = (double) this.getGroup().getEnvironment().getCells().length; + uniformGen = new UniformGen(pilot.getRandomStream(), new UniformDist(0,nbCell-1)); + } + + public void doProcess(PikesGroup group) { + Cell[] cells = group.getEnvironment().getCells(); + for (int i=0; i < initialNumberOfPikes ;i++){ + int ageAtCreation = (int)(12+group.getPilot().getCurrentTime()-group.getMonthOfBirth())%12 +12*(i%5); + //int ageAtCreation =(int) (12+Pilot.getCurrentTime()-group.getMonthOfBirth())%12; + double weightAtCreation = 2*group.getWeightAtAgeThreshold() * (ageAtCreation+12) / 12; + Pike newPike = new Pike(group.getPilot(), cells[(int)Math.round(uniformGen.nextDouble())], + ageAtCreation, weightAtCreation); + group.addAquaNism(newPike); + } + } +}