/* * #%L * IsisFish data * %% * Copyright (C) 2020 Ifremer, CodeLutin * %% * 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 * . * #L% */ package rules; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import scripts.SiMatrix; import java.util.*; import org.nuiton.math.matrix.*; import fr.ifremer.isisfish.simulator.*; import fr.ifremer.isisfish.types.TimeStep; import fr.ifremer.isisfish.types.Month; import fr.ifremer.isisfish.entities.*; import fr.ifremer.isisfish.rule.AbstractRule; import fr.ifremer.isisfish.util.Doc; import fr.ifremer.isisfish.*; import resultinfos.*; /** * Cantonnement.java * * Remplace aussi Cantonnement Engin * * Created: 30 novembre 2006 * * @author anonymous <anonymous@labs.libre-entreprise.org> * @version $Revision: 1.5 $ * * Last update: $Date: 2007-11-02 17:41:41 $ * by : $Author: bpoussin $ */ public class MultiLevelsMPANetwork_SarGDL_SpillOver extends AbstractRule { /** to use log facility, just put in your code: log.error("..."); */ static private Log log = LogFactory.getLog(MultiLevelsMPANetwork_SarGDL_SpillOver.class); @Doc(value="Cellules de fermeture Integrale (Nom des zones séparés par ,)") public String param_zones_integral = ""; @Doc(value="Cellules de fermeture Partiel 1(Nom des zones séparés par ,)") public String param_zones_partiel1 = ""; @Doc(value="Cellules de fermeture Partiel 2(Nom des zones séparés par ,)") public String param_zones_partiel2 = ""; //@Doc(value="Population concernées") //public Population param_population = null; // @Doc(value="Suffixe du nom de metier à utiliser, 'integral', ou 'partiel1' ou 'partiel2'") // public String param_mode = "integral"; @Doc(value="Begin step") public TimeStep param_beginStep = new TimeStep(0); @Doc(value="End step") public TimeStep param_endStep = new TimeStep(119); @Doc(value="Begin month") public Month param_beginMonth = Month.JANUARY; @Doc(value="End month") public Month param_endMonth = Month.DECEMBER; // zone de fermeture protected List zonesFermeturesIntegrale; protected Set cellsFermeturesIntegrale; protected List zonesFermeturesPartiel1; protected Set cellsFermeturesPartiel1; protected List zonesFermeturesPartiel2; protected Set cellsFermeturesPartiel2; // liste des noms des metiers concernes protected Set metierConcernes; protected Set metierConcernesPartiel1; protected Set metierConcernesPartiel2; // ensemble des cellules adjacentes à param_zone protected Set cellsAdjIntegrale; protected Set cellsAdjPartiel1; protected Set cellsAdjPartiel2; // Ajouter un boolean qui assure que la post-action ne sera faite qu'une fois pour tous les metiers ET TOUTES LES REGLES cantonnement public static boolean onlyOnPostActionCantonnementIntegralDone = false; protected String [] necessaryResult = { // put here all necessary result for this rule // example: // MatrixBiomass.NAME, // MatrixNetValueOfLandingsPerStrategyMet.NAME MatrixNoActivity.NAME }; @Override public String[] getNecessaryResult() { return this.necessaryResult; } /** * Permet d'afficher a l'utilisateur une aide sur la regle. * @return L'aide ou la description de la regle */ @Override public String getDescription() throws Exception { // Pour info inspiree de fermeture saisiniere de zone qui peut être réduite à un engin // et a certaines années de la simulation // Reseau d'amp de cellules inetgrales, partiel 1 et partiel2 - CANTONNEMENT INTEGRAL POUR SAR GDL // Charlotte: prise en compte du débordement d adulte et du repport de l effort de pêche // Charlotte: il faudrait renommer cette règle "AMP spillover" ou autre, pour ne pas la confondre avec cantonnement // Stephanie : en entree une liste de cellules de la pecherie (param_zone) par type de protection // hypotheses : // pas de cellules de protection dans les zones adjacentes // tous les metiers ont une zone metier = zone region et tous les metiers initiaux // de la base sont dupliqués en 3 (Metier, Metier_Integral, Metier_partiel1, Metier_partiel2) // une flottille par Metier initial qui a pour metiers possibles = Metier, Metier_Integral, Metier_partiel1, Metier_partiel2 // ou une flottille qui contient plusieurs Metiers initiaux (recreational fishing) et qui a tous les metiers possibles associés à ces métiers initiaux // une strategie par flottille Metier avec un effort a 1 sur Metier et 0 sur les autres Metier_Integral, Metier_partiel1, Metier_partiel2 // ou une strategie qui contient plusieurs Metiers initiaux (recreational fishing) et qui a tous les metiers possibles associés à ces métiers initiaux // Report de l'effort de l'ensemble des cellules sur les cellules adjacentes des cellules fermées à la peche // nom de la regle Cantonnement_Integral_SarGDL return "Cantonnement: can be used to Cantonnement with gear if you put gear in parameter"; } /** * Appelé au démarrage de la simulation, cette méthode permet d'initialiser * des valeurs * @param context La simulation pour lequel on utilise cette regle */ @Override public void init(SimulationContext context) throws Exception { // make sure mode is lower case param_mode = param_mode.toLowerCase(); // .toLowerCase() : CA SERT A QUOI ? //A CODER : remplacer par // si param_zones_integral != 0 alors tous les métiers sont concernés par la regle // else si param_zones_partiel2 != 0 alors trawl, boat gillnet et spearfishing sont concernés // else (si param_zones_partiel1 != 0) alors trawl est concerné metierConcernes = new HashSet<>(); if ("partiel1".equals(param_mode)) { metierConcernes.add("Trawl".toLowerCase()); } else if ("partiel2".equals(param_mode)) { metierConcernes.add("Trawl".toLowerCase()); metierConcernes.add("Boat gillnet".toLowerCase()); metierConcernes.add("Spear fishing".toLowerCase()); } // liste des metiers concernés par partiel1 et partiel2 metierConcernesPartiel1 = new HashSet<>(); metierConcernesPartiel1.add("Trawl".toLowerCase()); metierConcernesPartiel2 = new HashSet<>(); metierConcernesPartiel2.add("Trawl".toLowerCase()); metierConcernesPartiel2.add("Boat gillnet".toLowerCase()); metierConcernesPartiel2.add("Spear fishing".toLowerCase()); log.error("Liste des métiers restreint par '" + param_mode + "': " + metierConcernes); // A faire pour tous les types de zones - A VERIFIER zonesFermeturesIntegrale = new ArrayList<>(); ZoneDAO zoneDAO = context.getZoneDAO(); String[] zoneNames = param_zones_integrale.split("[,;]"); for (String zoneName : zoneNames) { zoneName = zoneName.trim(); Zone zone = zoneDAO.findByName(zoneName); if (zone == null) { throw new IsisFishException("Impossible de trouver la zone: " + zoneName); } zonesFermeturesIntegrale.add(zone); } zonesFermeturesPartiel1 = new ArrayList<>(); ZoneDAO zoneDAO = context.getZoneDAO(); String[] zoneNames = param_zones_partiel1.split("[,;]"); for (String zoneName : zoneNames) { zoneName = zoneName.trim(); Zone zone = zoneDAO.findByName(zoneName); if (zone == null) { throw new IsisFishException("Impossible de trouver la zone: " + zoneName); } zonesFermeturesPartiel1.add(zone); } zonesFermeturesPartiel2 = new ArrayList<>(); ZoneDAO zoneDAO = context.getZoneDAO(); String[] zoneNames = param_zones_partiel2.split("[,;]"); for (String zoneName : zoneNames) { zoneName = zoneName.trim(); Zone zone = zoneDAO.findByName(zoneName); if (zone == null) { throw new IsisFishException("Impossible de trouver la zone: " + zoneName); } zonesFermeturesPartiel2.add(zone); } // A CODER zonesFermetures = reunion des zones de Fermetures zonesFermetures = new ArrayList<>(); } /** * La condition qui doit etre vrai pour faire les actions. * * @param context la simulation pour lequel on utilise cette regle * @param step le pas de temps courant * @param metier le metier concerné * @return vrai si on souhaite que les actions soit faites */ @Override public boolean condition(SimulationContext context, TimeStep step, Metier metier) throws Exception { if (step.before(param_beginStep)) { return false; } else if (step.after(param_endStep)) { return false; } if (step.getMonth().before(param_beginMonth)) { return false; } else if (step.getMonth().after(param_endMonth)) { return false; } // evidement la regle ne s'applique pas sur les metiers integral et partiels codes dans la base pour la reallocation d'effort.. if (StringUtils.endsWithAny(metier.getName(), "integral", "partiel1", "partiel2")) { return false; } // la règle s'applique si le métier est dans metier concerné if (!metierConcernes.isEmpty() && !metierConcernes.contains(metier.getName().toLowerCase())) { log.error(" MultiLevelsMPANetwork_SarGDL_SpillOver: Metier '" + metier.getName() + "' non autorisé en mode " ); return false; } List cellMetiers = metier.getMetierSeasonInfo(step.getMonth()).getCells(); cellsFermetures = getZonesCells(zonesFermetures); cellMetiers.retainAll(cellsFermetures); boolean result = !Collections.disjoint(cellMetiers, cellsFermetures); // attention ce test n'est pas optimise car toutes les cellules ne concernent pas tous les metiers if (!result) { log.error("MultiLevelsMPANetwork_SarGDL_SpillOver: les zones metier et zonesMPA disjointes"); } return result; } /** * Si la condition est vrai alors cette action est executee avant le pas * de temps de la simulation. * * @param context la simulation pour lequel on utilise cette regle * @param step le pas de temps courant * @param metier le metier concerné */ @Override public void preAction(SimulationContext context, TimeStep step, Metier metier) throws Exception { //reset du boolean post action onlyOnPostActionCantonnementIntegralDone = false; MetierDAO metierDAO = context.getMetierDAO(); MetierMonitor metierMon = context.getMetierMonitor(); // pour metier MetierSeasonInfo infoMetier = metier.getMetierSeasonInfo(step.getMonth()); List cellMetiers = infoMetier.getCells(); //Set cellsFermetures = getZonesCells(zonesFermetures); int nbCellZoneMetierAvantFermeture = cellMetiers.size(); //Algo : // quelque soit le metier (metiersConcernes) // SI integrale uniquement (param_zones_integrale!=0 et param_zones_partiel1=0 et param_zones_partiel2!=0) (tous les métiers) // alors metier, metier_integral vont etre modifies // zone_metier_new = zone_metier - zonesFermetures, effort_metier_new = effort_metier*(1-nbCellzonesFermeturesIntegrale/nbCellZoneMetier) // zone_metier_integral = zoneAdj(zonesFermeturesIntegrale), effort_metier_integral = effort_metier*nbCellzonesFermeturesIntegrale/nbCellZoneMetier // ELSE // SI metier dans metiersConcernesPartiel2 // ET SI partiel2 uniquement (param_zones_integrale=0 et param_zones_partiel1=0 et param_zones_partiel2!=0) // alors metier, metier_partiel2 vont etre modifies // zone_metier_new = zone_metier - zonesFermetures, effort_metier_new = effort_metier*(1-nbCellzonesFermeturesPartiel2/nbCellZoneMetier) // zone_metier_partiel2 = zoneAdj(zonesFermeturesPartiel2), effort_metier_partiel2 = effort_metier*nbCellzonesFermeturesPartiel2/nbCellZoneMetier // ELSE ET SI partiel2 et partiel1 uniquement (param_zones_integrale=0 et param_zones_partiel1!=0 et param_zones_partiel2!=0) // alors // SI metier dans metiersConcernesPartiel1 // alors metier, metier_partiel1, metier_partiel2 vont etre modifies // zone_metier_new = zone_metier - zonesFermeturesPartiel1 -zonesFermeturesPartiel2 , effort_metier_new = effort_metier*(1-(nbCellzonesFermeturesPartiel1+nbCellzonesFermeturesPartiel2)/nbCellZoneMetier) // zone_metier_partiel1 = zoneAdj(zonesFermeturesPartiel1), effort_metier_Partiel1 = effort_metier*nbCellzonesFermeturesPartiel1/nbCellZoneMetier // zone_metier_partiel2 = zoneAdj(zonesFermeturesPartiel2), effort_metier_partiel2 = effort_metier*nbCellzonesFermeturesPartiel2/nbCellZoneMetier // ELSE (metier dans metiersConcernesPartiel2 uniquement) // metier, metier_partiel2 vont etre modifies // zone_metier_new = zone_metier - zonesFermeturesPartiel1 -zonesFermeturesPartiel2 , effort_metier_new = effort_metier*(1-(nbCellzonesFermeturesPartiel2)/nbCellZoneMetier) // zone_metier_partiel2 = zoneAdj(zonesFermeturesPartiel2), effort_metier_partiel2 = effort_metier*nbCellzonesFermeturesPartiel2/nbCellZoneMetier // ELSE ET SI partiel2 et partiel1 et integral (param_zones_integrale!=0 et param_zones_partiel1!=0 et param_zones_partiel2!=0) // alors // SI metier dans metiersConcernesPartiel1 // alors metier, metier_integral, metier_partiel1, metier_partiel2 vont etre modifies // zone_metier_new = zone_metier - zonesFermetures, effort_metier_new = effort_metier*(1-nbCellzonesFermetures/nbCellZoneMetier) // zone_metier_integral = zoneAdj(zonesFermeturesIntegrale), effort_metier_integral = effort_metier*nbCellzonesFermeturesIntegrale/nbCellZoneMetier // zone_metier_partiel1 = zoneAdj(zonesFermeturesPartiel1), effort_metier_partiel1 = effort_metier*nbCellzonesFermeturesPartiel1/nbCellZoneMetier // zone_metier_partiel2 = zoneAdj(zonesFermeturesPartiel2), effort_metier_partiel2 = effort_metier*nbCellzonesFermeturesPartiel2/nbCellZoneMetier // ELSE (metier dans metiersConcernesPartiel2 uniquement) // metier, metier_integral, metier_partiel2 vont etre modifies // zone_metier_new = zone_metier - zonesFermeturesIntegrale -zonesFermeturesPartiel2 , effort_metier_new = effort_metier*(1-(nbCellzonesFermeturesIntegrale+nbCellzonesFermeturesPartiel2)/nbCellZoneMetier) // zone_metier_integral = zoneAdj(zonesFermeturesIntegrale), effort_metier_integral = effort_metier*nbCellzonesFermeturesIntegrale/nbCellZoneMetier // zone_metier_partiel2 = zoneAdj(zonesFermeturesPartiel2), effort_metier_partiel2 = effort_metier*nbCellzonesFermeturesPartiel2/nbCellZoneMetier // ELSE // SI metier dans metiersConcernesPartiel1 // ET SI partiel1 uniquement (param_zones_integrale=0 et param_zones_partiel1!=0 et param_zones_partiel2=0) // alors metier, metier_partiel1 vont etre modifies // zone_metier_new = zone_metier - zonesFermetures, effort_metier_new = effort_metier*(1-nbCellzonesFermeturesPartiel1/nbCellZoneMetier) // zone_metier_partiel1 = zoneAdj(zonesFermeturesPartiel1), effort_metier_partiel1 = effort_metier*nbCellzonesFermeturesPartiel1/nbCellZoneMetier // ET SI partiel1 et integral uniquemnt (param_zones_integrale!=0 et param_zones_partiel1!=0 et param_zones_partiel2=0) // alors metier, metier_integral, metier_partiel1 vont etre modifies // zone_metier_new = zone_metier - zonesFermeturesIntegrale -zonesFermeturesPartiel1 , effort_metier_new = effort_metier*(1-(nbCellzonesFermeturesIntegrale+nbCellzonesFermeturesPartiel1)/nbCellZoneMetier) // zone_metier_integral = zoneAdj(zonesFermeturesIntegrale), effort_metier_integral = effort_metier*nbCellzonesFermeturesIntegrale/nbCellZoneMetier // zone_metier_partiel1 = zoneAdj(zonesFermeturesPartiel1), effort_metier_partiel1 = effort_metier*nbCellzonesFermeturesPartiel1/nbCellZoneMetier // pour metier_ intergral String integralMetierName = metier.getName() + "_" + param_mode; // "_Integral" Metier metierIntegral = metierDAO.findByName(integralMetierName); MetierSeasonInfo infoMetierIntegral = metierIntegral.getMetierSeasonInfo(step.getMonth()); ////////////////////////////////////////////////////////////////////////////////////////// // 1. mise à jour de la zone metier Metier_integral = reunion des cellules adjacentes //ZONE_METIER_integral = { CELLULES ADJACENTES } // Boucler sur les cellules de param_zone et pour chaque cellule, trouver les cellules adjacentes, faire la reunion des cellules adjacentes et enlever les doublons de cellules // et à la fin de la boucle, tu as la zone de l'ensemble des cellules adjacentes ///////////////////////////////////////////////////////////////////////////////////////// // Définition des cellules adjacentes autour de chaque AMP // (i.e. chaque cellule comprise dans la zone de cantonnement) cellsAdj = getCellulesAdjacentes(context, cellsFermetures); /////////////////////////////////////////////////////////////////////////////////////////// // 2. mettre a jour la zone Metier // Zone_Metier = ZoneMetier - ZONE_METIER_integral cellMetiers.removeAll(cellsFermetures); cellMetiers.removeAll(cellsAdj); // zone metier 1 = zone met - zone canto - zone adj // zone metier 2 = cellsAdj (où s appliquent la copie des metiers en zone metier 1) ////////////////////////////////////////////////////////////////////////////////////////// // REPORT DE L EFFORT DE PECHE ///////////////////////////////////////////////////////////////////////////////////////// // 3. l effort de pêche des métiers interdits dans l AMP est redistribué équitablement dans les cellules composant la zone adj // CAS ISIS: l effort de toute la zone AMP (de totues les cellules AMPs) est redistribué équitablement dans toutes les cellules de la zone ADJ // les metiers en zone adj sont les mêmes que en zone met 1, mais avec un effort différent // D où la création de nouveaux métiers (identiques aux métiers de la zone met 1) pour cette zone adj // ICI: code pour assigner les métiers V2 dans la zone adj // NB: ce seront les métiers qui auront été interdits dans l AMP (pas les memes metiers dans chaque simulation) // a. recuperer la strategie qui contient metier (Metier) - par son nom, if (metier == boal_gillnet) || ( ) || () then nom_strategie = "recreational fishing"; else nom_strategie = 'nom_metier' // b. calculer la proportion de l'effort de metier sur les cellules de param_zone prop_metier= #param_zone/#zone_Metier(avant fermeture) - cette prop doit etre calulee avant chgt des zones // c. Effort(metier) = Effort(metier)*(1-prop_metier) // d. Effort(metier_Integral) = Effort(metier)*prop_metier if (cellMetiers.size() != 0) { // si il reste des cellules metiers apres avoir retranché les cellules cantonnement ZoneDAO dao = context.getZoneDAO(); // // Create new empty zone for cantonnement // // CODER partie 1. String nameZoneCantIntegral = "ZoneCantonnement" + param_mode + "-" + metier.getName() + "-" + step.getStep(); Zone zoneAdj = dao.create(); zoneAdj.setName(nameZoneCantIntegral); zoneAdj.setCell(new ArrayList<>(cellsAdj)); List newZoneAdj = new ArrayList<>(); newZoneAdj.add(zoneAdj); infoMetierIntegral.setZone(newZoneAdj); log.error("Cantonnement: Creation de la zone " + nameZoneCantIntegral + " avec " + cellsAdj.size() + " cellules"); // rien à changer = 2. de l'algo String nameZoneCant = "ZoneCantonnement-" + metier.getName() + "-" + step.getStep(); Zone zoneCantonnement = dao.findByName(nameZoneCant); int cpt=0; while (zoneCantonnement != null) { cpt++; zoneCantonnement = dao.findByName(nameZoneCant + "-" + cpt); } zoneCantonnement = dao.create(); if (cpt > 0) { nameZoneCant += "-" + cpt; } zoneCantonnement.setName(nameZoneCant); log.error("Cantonnement: Creation de la zone " + zoneCantonnement); // // Remove prohibited zone and add not prohibited cell to zoneCantonnement // Collection zoneMetiers = infoMetier.getZone(); for (Iterator i = zoneMetiers.iterator(); i.hasNext();) { Zone zone = i.next(); // copy list cell to not modify original zone List tmpCells = new ArrayList<>(zone.getCell()); tmpCells.removeAll(cellsFermetures); zoneCantonnement.addAllCell(tmpCells); i.remove(); } List newZone = new ArrayList<>(); newZone.add(zoneCantonnement); infoMetier.setZone(newZone); // FIN DE rien à changer = 2. de l'algo } else { // sinon toute la zone de pratique du metier est incluse dans zone Cantonnement // alors metier devient metier-nonactivite SiMatrix siMatrix = SiMatrix.getSiMatrix(context); MatrixND noActivity = metierMon.getOrCreateNoActivity(step, MatrixNoActivity.NAME, siMatrix.getStrategies(step), siMatrix.getMetiers(step)); metierMon.addforbiddenMetier(metier); List strategies = siMatrix.getStrategies(step); for (Strategy str : strategies) { StrategyMonthInfo info = str.getStrategyMonthInfo(step.getMonth()); double prop = info.getProportionMetier(metier); if (prop != 0) { noActivity.setValue(str , metier, prop); info.setProportionMetier(metier, 0); } } } // PARTIE 2. à CODER // a. StrategyDAO strategieDAO = context.getStrategyDAO(); Strategy strategie; if (metier.getName().equalsIgnoreCase("Boat line") || metier.getName().equalsIgnoreCase("Shore line") ||metier.getName().equalsIgnoreCase("Spear fishing")) { strategie = strategieDAO.findByName("Recreational fishing"); } else { strategie = strategieDAO.findByName(metier.getName()); } // b. int nbCellParamZone = cellsFermetures.size(); double prop_metier = (double)nbCellParamZone / (double)nbCellZoneMetierAvantFermeture; log.error("Cantonnement: Proportion metier = " + prop_metier); // c. StrategyMonthInfo strategyMonthInfo = strategie.getStrategyMonthInfo(step.getMonth()); double effortMetier = strategyMonthInfo.getProportionMetier(metier); effortMetier = effortMetier * (1 - prop_metier); strategyMonthInfo.setProportionMetier(metier, effortMetier); // d. double effortMetierIntegral = effortMetier * prop_metier; strategyMonthInfo.setProportionMetier(metierIntegral, effortMetierIntegral); // fin de preAction } /** * Si la condition est vrai alors cette action est executée apres le pas * de temps de la simulation. * * @param context La simulation pour lequel on utilise cette regle * @param step le pas de temps courant * @param metier le metier concerné */ @Override public void postAction(SimulationContext context, TimeStep step, Metier metier) throws Exception { ////////////////////////////////////////////////////////////////////////////////////////// // SPILLOVER ///////////////////////////////////////////////////////////////////////////////////////// // Spillover = débordement d adultes d une AMPs dans les zones adjacentes // Lorsque la densité à l interieur de la zone AMP est superieure à 2.46 (Claudet et al., 2008) // fois la densité moyenne de toutes les cellules des zones de présence (1 zone par cellule de présence) // alors l excédent d'abondance sera redistribué équitablement dans la zone adj // pour chaque cellule de param_zone, N(cell), if (N(cell)/surface_cellule > 2.46 *(N(t)-N(param_zone))/(#cellules(zone_presence)-#cellules(param_zone)) then // Surplus = N(cell)/surface_cellule - 2.46*(N(t)-N(param_zone))/(#cellules(zone_presence)-#cellules(param_zone)) à redistribuer dans la zone adjacente de la cellule (Zone-adj_cell) // 1. zone adjacente à cell // 2. N(cell) = N(cell) - Surplus // 3. boucle sur cell_adj toutes les cellules de la zone adjacente de cell (cell_adj in Zone-adj_cell) N(cell_adj) = N(cell_adj) + Surplus/#cellules(Zone-adj_cell) if (onlyOnPostActionCantonnementIntegralDone) { onlyOnPostActionCantonnementIntegralDone = true; log.error("Cantonnement: post action for step " + step); // PopulationMonitor popMonitor = context.getPopulationMonitor(); MatrixND N = popMonitor.getN(param_population); MatrixND NgroupAllZones = N.sumOverDim(1).reduceDims(1); // somme toutes les zones List zonePresence = param_population.getPopulationZone(); int nbCellZonePresence = zonePresence.size(); // ok si une zone == une cell int nbCellZoneParam = cellsFermetures.size(); // indexation des zones par les cellules Map zoneForCell = new HashMap<>(); for (Zone zone : zonePresence) { List cells = zone.getCell(); if (cells.size() != 1) { throw new IsisFishException("L'algo ne peut pas fonctionner si la zone " + zone.getName() + " n'a pas exactement une zone"); } Cell cell = cells.get(0); if (zoneForCell.get(cell) != null) { throw new IsisFishException("Collision de cellule " + zone); } zoneForCell.put(cell, zone); } // pour chaque cellule de la zone, on recherche la zone associées qui contient uniquement // cette cellule pour pouvoir rechercher l'abondance avec cette zone (soit Ncell) for (PopulationGroup group : param_population.getPopulationGroup()) { double Nt = NgroupAllZones.getValue(group); // detenrimination de param_zone sur les zones de présence // param_zone n'est pas forcement une zone de présence double NparamZone = 0; for (Cell cellParamZone : cellsFermetures) { Zone zoneAssociee = zoneForCell.get(cellParamZone); if (zoneAssociee != null) { NparamZone += N.getValue(group, zoneAssociee); } } double densiteMoyenne = (Nt - NparamZone) / (double) (nbCellZonePresence - nbCellZoneParam); for (Cell cellParamZone : cellsFermetures) { Zone zoneAssociee = zoneForCell.get(cellParamZone); if (zoneAssociee != null) { double Ncell = N.getValue(group, zoneAssociee); log.error("Cantonnement: Ncell / densiteMoyenne= " + Ncell + "," + densiteMoyenne + ", " + Ncell / densiteMoyenne); if (Ncell > 2.46 * densiteMoyenne) { // repartition du surplus double surplus = (Ncell / nbCellZoneParam) - 2.46 * densiteMoyenne; // 2. N(cell) = N(cell) - Surplus N.setValue(group, zoneAssociee, Ncell - surplus); // 3. boucle sur cell_adj toutes les cellules de la zone adjacente de cell // (cell_adj in Zone-adj_cell) N(cell_adj) = N(cell_adj) + Surplus/#cellules(Zone-adj_cell) for (Cell cellAdj : cellsAdj) { Zone zoneForCellAdj = zoneForCell.get(cellAdj); double NzoneAdj = N.getValue(group, zoneForCellAdj); NzoneAdj += surplus / cellsAdj.size(); N.setValue(group, zoneForCellAdj, NzoneAdj); log.error("Cantonnement: Repartition du surplus dans la cellule " + cellAdj.getName()); } } } } } popMonitor.setN(param_population, N); } } /** * Retourne la liste des cellules de plusieurs zones. */ protected Set getZonesCells(Collection zones) { Set cells = new HashSet<>(); for (Zone zone : zones) { cells.addAll(zone.getCell()); } return cells; } /** * Retourne les cellules adjacentes de toutes les cellules d'une zone. */ protected Set getCellulesAdjacentes(SimulationContext context, Collection cellulesFermeture) { // resultat Set cellulesAdjacentesTotal = new HashSet<>(); // pour l'unicité des cellules trouvées // récuperation de toutes les cellules de la base FisheryRegion fisheryRegion = context.getFisheryRegionDAO().findAll().get(0); List allCells = fisheryRegion.getCell(); // calcul des adjacentes for (Cell celluleZoneParam : cellulesFermeture) { Set cellulesAdjacentes = getCellulesAdjacentes(fisheryRegion, allCells, celluleZoneParam); log.error("Cantonnement: - nombre de cellules adjacentes de '" + celluleZoneParam.getName() + "': " + cellulesAdjacentes.size()); cellulesAdjacentesTotal.addAll(cellulesAdjacentes); } // retrait des cellules de bases car les cellules adjacentes de la zone // ne peuvent pas contenir les cellules de la zone cellulesAdjacentesTotal.removeAll(cellulesFermeture); log.error("Cantonnement: => total pour les '" + cellulesFermeture.size() + "' cellules de fermeture : " + cellulesAdjacentesTotal.size() + " cellules adjacentes"); return cellulesAdjacentesTotal; } /** * Retourne les cellules adjacentes d'une seule cellules. */ protected Set getCellulesAdjacentes(FisheryRegion fisheryRegion, List allCells, Cell cell) { Set cellulesAdjacentes = new HashSet<>(); for (Cell singleCell : allCells) { if (isCellulesAdjacentes(fisheryRegion, singleCell, cell)) { cellulesAdjacentes.add(singleCell); } } return cellulesAdjacentes; } /** * Retourne 'vrai' si deux cellules sont adjacentes. */ protected boolean isCellulesAdjacentes(FisheryRegion fisheryRegion, Cell cell1, Cell cell2) { float resX = fisheryRegion.getCellLengthLongitude(); float resY = fisheryRegion.getCellLengthLatitude(); float x1 = cell1.getLongitude(); float y1 = cell1.getLatitude(); float x2 = cell2.getLongitude(); float y2 = cell2.getLatitude(); // | case1 | case 2 | case 3 | // | case4 | CELL | case 5 | // | case6 | case7 | case 8 | boolean result = (isAdjCoord(x1 + resX, x2) && isAdjCoord(y1 + resY, y2)) || // case 1 (x1 == x2 && isAdjCoord(y1 + resY, y2)) || // case 2 (isAdjCoord(x1 - resX, x2) && isAdjCoord(y1 + resY, y2)) || // case 3 (isAdjCoord(x1 + resX, x2) && y1 == y2) || // case 4 (isAdjCoord(x1 - resX, x2) && y1 == y2) || // case 5 (isAdjCoord(x1 + resX, x2) && isAdjCoord(y1 - resY, y2)) || // case 6 (x1 == x2 && isAdjCoord(y1 - resY, y2)) || // case 7 (isAdjCoord(x1 - resX, x2) && isAdjCoord(y1 - resY, y2)); // case 8 return result; } // Lors de la deffinition des zones, il y a un arrondit a 10-3 pres protected boolean isAdjCoord(float v1, float v2) { return Math.abs(v1 - v2) < 0.001; } }