Commit 653aa13a authored by Dumoulin Nicolas's avatar Dumoulin Nicolas
Browse files

Generator of input data from patches generated by python Generator

of our project.
parent edda54e8
Pipeline #36838 failed with stages
in 2 minutes and 27 seconds
......@@ -7,12 +7,16 @@ apply plugin: 'application'
mainClassName = 'fr.inrae.agriterix.simulator.Simulator'
repositories {
// GeoTools repository for shapefile manipulation. Need to be on first position to avoid dependency lookup failure.
maven {
url "https://repo.osgeo.org/repository/release/"
}
jcenter()
mavenCentral()
//maven {
//url "https://maven.scijava.org/content/repositories/public/"
//}
}
}
dependencies {
testImplementation 'junit:junit:4.13'
......@@ -20,6 +24,8 @@ dependencies {
implementation 'org.apache.commons:commons-lang3:3.11'
implementation 'commons-cli:commons-cli:1.4'
implementation 'com.thoughtworks.xstream:xstream:1.4.15'
// https://mvnrepository.com/artifact/org.geotools/gt-shapefile
implementation group: 'org.geotools', name: 'gt-shapefile', version: '25.1'
// https://mvnrepository.com/artifact/ch.systems.cisd/jhdf5
//implementation group: 'cisd', name: 'jhdf5', version: '19.04.0'
implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.34.0'
......
package fr.inrae.agriterix.generator;
import fr.inrae.agriterix.simulator.CulturalPractice;
import fr.inrae.agriterix.simulator.Farm;
import fr.inrae.agriterix.simulator.Farmer;
import fr.inrae.agriterix.simulator.Flow;
import fr.inrae.agriterix.simulator.GeoArea;
import fr.inrae.agriterix.simulator.Parameters;
import fr.inrae.agriterix.simulator.Patch;
import fr.inrae.agriterix.simulator.Product;
import fr.inrae.agriterix.simulator.Ratio;
import fr.inrae.agriterix.simulator.Simulator;
import fr.inrae.agriterix.simulator.Stocks;
import fr.inrae.agriterix.simulator.TimeUnit;
import fr.inrae.agriterix.simulator.Unit;
import fr.inrae.agriterix.simulator.dynamics.Dynamics;
import fr.inrae.agriterix.simulator.dynamics.FlowDynamics;
import fr.inrae.agriterix.simulator.dynamics.MarketDynamics;
import fr.inrae.agriterix.simulator.dynamics.PopulationDynamics;
import fr.inrae.agriterix.simulator.dynamics.ProductionDynamics;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.opengis.feature.simple.SimpleFeature;
import umontreal.ssj.rng.MRG32k3a;
import umontreal.ssj.rng.RandomStreamBase;
public class Generator {
/**
* Build a list of farmers with given initial distribution of ages (starting from 18 yo).
* @ages array of effectives for each ages
* @area the GeoArea instance for initializing the farmers
* @popTotal the total number of farmers to build.
*/
private static List<Farmer> generate_farmers(int[] ages, GeoArea area, int popTotal) {
int sum = Arrays.stream(ages).sum();
double[] probas = Arrays.stream(ages).asDoubleStream().map(i -> i/sum).toArray();
int[] population = Arrays.stream(probas).mapToInt(i -> (int)Math.round(i * popTotal)).toArray();
List<Farmer> farmers = new ArrayList<>();
for (int i = 0; i < population.length; i++) {
for (int j = 0; j < population[i]; j++) {
Farm farm = new Farm(area);
farmers.add(new Farmer(i+18, farm));
}
}
return farmers;
}
/**
* Randomly pick and remove a farmer in the given list
* @param rng the RNG to use
* @param farmers the initial list of farmers
* @param id_expl the ID to set to the picked farmer.
* @return The farmer
*/
private static Farmer pickFarmer(RandomStreamBase rng, List<Farmer> farmers, int id_expl) {
Farmer farmer = farmers.remove(rng.nextInt(0, farmers.size()-1));
farmer.setId(id_expl);
return farmer;
}
/**
* Generates patches in the given geo area.
* @param rng The RNG used for picking the farmer
* @param shapefile The shapefile containing the patches
* @param area The initial area where put the patches
* @param farmers The list of farmers to assign on the patches (unmodified)
* @return the list of products produced by the patches
* @throws IOException
*/
public static List<Product> generate_patches(RandomStreamBase rng, String shapefile, GeoArea area, List<Farmer> farmers) throws IOException {
Map<String, Product> products = new HashMap<>();
Map<Integer, Farmer> farmersID = new HashMap<>();
List<Patch> patches = new ArrayList<>();
// working on a copy of farmers, because we will remove them when randomly picking
List<Farmer> farmers_toPick = new ArrayList<>(farmers);
// loading the shapefile
FileDataStore dataStore = FileDataStoreFinder.getDataStore(new File(shapefile));
SimpleFeatureSource featureSource = dataStore.getFeatureSource();
SimpleFeatureCollection collection = featureSource.getFeatures();
SimpleFeatureIterator iterator = collection.features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
int id_expl = ((Long) feature.getAttribute("id_expl")).intValue();
String codecult = (String) feature.getAttribute("codecultco");
Double surface = (Double) feature.getAttribute("surf_ilot");
int patch_id = Integer.parseInt((String) feature.getAttribute("ID_PARCEL"));
// Store the product if needed, retrieve it otherwise
Product product;
if (products.containsKey(codecult)) {
product = products.get(codecult);
} else {
product = new Product(codecult, Unit.Kg);
products.put(codecult, product);
}
// Store the farmer if needed, retrieve it otherwise
Farmer farmer;
if (farmersID.containsKey(id_expl)) {
farmer = farmersID.get(id_expl);
} else {
farmer = pickFarmer(rng, farmers_toPick, id_expl);
farmersID.put(id_expl, farmer);
}
// Create and add the patch to the area
Patch patch = new Patch(area, surface.floatValue(), CulturalPractice.I, product, farmer.getFarm(), patch_id);
patches.add(patch);
area.getPatches().add(patch);
}
} finally {
iterator.close();
}
return new ArrayList<>(products.values());
}
/**
* Creates a dummy flow for a given product
* @param product
* @param maximum
* @return
*/
private static Flow createFlow(Product product, float maximum) {
Stocks quantities1 = new Stocks();
Map<Product, Float> required1 = new HashMap<>();
Map<Product, Float> produced1 = new HashMap<>();
required1.put(product, 1.f);
produced1.put(product, 1.f);
Ratio ratio1 = new Ratio(required1, produced1);
List<Flow.Input> inputs1 = new ArrayList<>();
List<Product> outputs1 = new ArrayList<>();
inputs1.add(new Flow.Input(product, maximum));
outputs1.add(product);
return new Flow(inputs1, quantities1, outputs1, ratio1, "Commerce");
}
public static void main(String[] args) throws IOException {
// farmers ages from MSA for France, starting at 18 year old
int[] ages_2018 = {1, 76, 268, 579, 1079, 1493, 1973, 2432, 3059, 3592, 4236, 4717, 5440, 5904, 6419, 6945, 7574, 7847, 8414, 8704, 8992, 8782, 8821, 9069, 9236, 9741, 10569, 11458, 12058, 12623, 12927, 13351, 13637, 14446, 15461, 16145, 17113, 17017, 17163, 17660, 17350, 17190, 16147, 12294, 10037, 6746, 5509, 4670, 3720, 2830, 2401, 2181, 1856, 1584, 1209, 790, 665, 595, 496, 390, 333, 346, 303, 246, 238, 205, 201, 175, 146, 125, 92, 82, 75, 55, 50, 36, 36, 26, 25, 18, 13, 10, 11};
GeoArea geoarea = new GeoArea("Puy-de-Dome");
RandomStreamBase rng = new MRG32k3a();
List<Farmer> farmers = generate_farmers(ages_2018, geoarea, 6160);
List<Product> products = Generator.generate_patches(rng, "data/input/generator/patches/patches.shp", geoarea, farmers);
for (Product product : products) {
geoarea.getFlows().add(createFlow(product, 100.f));
}
List<Dynamics> dynamics = new ArrayList<>();
//dynamics.add(new PopulationDynamics());
dynamics.add(new ProductionDynamics());
dynamics.add(new MarketDynamics());
dynamics.add(new FlowDynamics());
Simulator simulator = new Simulator(new Parameters(0, dynamics), farmers);
simulator.serializeXML(Files.newOutputStream(Paths.get("data/input/generator/simulator.xml")));
System.out.println("# patches: " + simulator.geoAreas().get(0).getPatches().size());
System.out.println("# farmers: " + simulator.getFarmers().size());
System.out.println("# products: " + simulator.getGlobal().getInputs().size());
System.out.println("# flows: " + simulator.geoAreas().get(0).getFlows().size());
for (int i = 0; i < 50; i++) {
simulator.step(TimeUnit.YEAR);
}
}
}
......@@ -22,6 +22,10 @@ public class Farmer {
return id;
}
public void setId(int id) {
this.id = id;
}
public Farm getFarm() {
return farm;
}
......
......@@ -33,6 +33,30 @@ public class Simulator {
private transient MutableInt timestep;
private transient XStream xstream;
public Simulator(Parameters parameters, List<Farmer> farmers) {
this.parameters = parameters;
this.geoAreas = new ArrayList<>();
this.farms = new ArrayList<>();
for (Farmer farmer : farmers) {
if (!farms.contains(farmer.getFarm())) {
farms.add(farmer.getFarm());
}
for (Patch patch : farmer.getFarm().getPatches()) {
if (!this.geoAreas.contains(patch.getGeoArea())) {
this.geoAreas.add(patch.getGeoArea());
}
}
}
this.farmers = farmers;
this.timestamp = java.time.LocalDateTime.now().toString();
this.dynamicsList = parameters.getDynamics();
this.initIgnoredFields();
for (Dynamics dynamics : dynamicsList) {
dynamics.setTimeStamp(timestamp);
}
this.global = createGlobal();
}
public Simulator(Parameters parameters, List<Farm> farms, List<Farmer> farmers) {
this.parameters = parameters;
this.farms = farms;
......@@ -162,6 +186,10 @@ public class Simulator {
public List<GeoArea> geoAreas() {
return geoAreas;
}
public Flow getGlobal() {
return global;
}
public static Simulator loadSimulator(InputStream input) {
XStream xstream = createXstream();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment