/* * #%L * IsisFish data * %% * Copyright (C) 2006 - 2014 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 fr.ifremer.isisfish.datastore.ResultStorage; import fr.ifremer.isisfish.entities.EffortDescription; import fr.ifremer.isisfish.entities.Metier; import fr.ifremer.isisfish.simulator.MetierMonitor; import fr.ifremer.isisfish.entities.MetierSeasonInfo; import fr.ifremer.isisfish.entities.StrategyMonthInfo; import fr.ifremer.isisfish.entities.Population; import fr.ifremer.isisfish.entities.PopulationGroup; import fr.ifremer.isisfish.entities.Result; import fr.ifremer.isisfish.entities.Species; import fr.ifremer.isisfish.entities.Strategy; import fr.ifremer.isisfish.entities.TargetSpecies; import fr.ifremer.isisfish.entities.Zone; import fr.ifremer.isisfish.rule.AbstractRule; import fr.ifremer.isisfish.simulator.PopulationMonitor; import fr.ifremer.isisfish.simulator.SimulationContext; import fr.ifremer.isisfish.types.Month; import fr.ifremer.isisfish.types.TimeStep; import fr.ifremer.isisfish.util.Doc; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.math.matrix.MatrixFactory; import org.nuiton.math.matrix.MatrixIterator; import org.nuiton.math.matrix.MatrixND; import org.nuiton.topia.*; import org.nuiton.util.*; import scripts.ResultName; import scripts.RuleUtil; import scripts.SiMatrix; /** * Cette regles tient compte de la taille minimum des poissons capturable. * * Created: 30 novembre 2006 * * @author smahevas * @version $Revision: 1.1 $ * * Last update: $Date: 2007-01-24 18:25:34 $ by : $Author: bpoussin $ * * Adaptation du TAC_OptionLO de SIgrid : TAC fixe pour 2010 à 2015 * */ public class TAC20102015HCR_Sole_OptionLO extends AbstractRule { /** to use log facility, just put in your code: log.info("..."); */ static private Log log = LogFactory.getLog(TAC20102015HCR_Sole_OptionLO.class); @Doc(value = "Begin step") public TimeStep param_beginStep = new TimeStep(0); @Doc(value = "End date") public TimeStep param_endStep = new TimeStep(180); @Doc(value = "Affected population") public Population param_pop = null; /** TAC in tonnes */ @Doc("TAC in tons 2010") public double param_tacInTons2010 = 4829; // First Year of simulation @Doc("TAC in tons 2011") public double param_tacInTons2011 = 4250; @Doc("TAC in tons 2012") public double param_tacInTons2012 = 4250; @Doc("TAC in tons 2013") public double param_tacInTons2013 = 4100; @Doc("TAC in tons 2014") public double param_tacInTons2014 = 3800; @Doc("TAC in tons 2015") public double param_tacInTons2015 = 3800; @Doc(value = "If 0, TAC is computed elsewhere, otherwise enter TAC for ISIS fleets") public double param_tacInKgs = 0; //after 2015 TAC is computed by HCR or fixed @Doc(value = "Proportion de survie") public double param_propSurvie = 0; @Doc(value = "Landings Obligation Implemented ?") public boolean param_LandingsObligation = false; public boolean param_DeMinimis = false; //Inputs required by this rule : // (Double) context.getValue("totOtherCatchStep_" + param_population.getName() + "_" + step.previous().getStep()); // computed in CapturesLongLinersNetters_Projection_Ratio // // THIS RULE RUNS ONLY IF CapturesLongLinersNetters_Projection_Ratio is applied // // Outputs provided by this rule : // context.setValue("tacInTons_" + param_population.getName() + "_2014", tacInTons); protected boolean affectation = false; protected String[] necessaryResult = { // put here all necessary result for this rule ResultName.MATRIX_CATCH_PER_STRATEGY_MET_PER_ZONE_POP, ResultName.MATRIX_DISCARDS_WEIGHT_PER_STR_MET_PER_ZONE_POP, ResultName.MATRIX_CATCH_WEIGHT_PER_STRATEGY_MET_PER_ZONE_MET // ResultName.MATRIX_BIOMASS, // ResultName.MATRIX_NET_VALUE_OF_LANDINGS_PER_STRATEGY_MET, }; @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 { return "If TAC is reached, price of fish is null"; } /** * Appele au demarrage de la simulation, cette methode permet * d'initialiser des valeurs de la * * @param context La simulation pour laquelle on utilise cette regle */ @Override public void init(SimulationContext context) throws Exception { } /** * @param context * @param date * @param param_species * @param metier * @return */ private boolean isCaptureDate(TimeStep step, Species species, Metier metier) { MetierSeasonInfo info = metier.getMetierSeasonInfo(step.getMonth()); TargetSpecies target = info.getSpeciesTargetSpecies(species); boolean result; if (target != null) { result = true; } else { result = false; } return result; } /** * 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 concerne * @return vrai si on souhaite que les actions soit faites */ @Override public boolean condition(SimulationContext context, TimeStep step, Metier metier) throws Exception { // read species in current session param_pop = (Population) context.getDB().findByTopiaId( param_pop.getTopiaId()); boolean result = false; if (step.before(param_beginStep)) { result = false; } else if (step.after(param_endStep)) { result = false; }else if(step.getMonth().equals(Month.JANUARY)){ // reinit priceSwitch at the beginning of each year context.setValue("priceSwitch"+param_pop.getName(),0); context.setValue("TACatteint"+param_pop.getName(),false); context.setValue(metier.getName()+param_pop.getName()+"flag",0); result = false; } else { // metier flag = 0 si pas concern par le TAC // metier flag = 1 si TAC atteint et rejet // metier flag = 2 si TAC atteint et interdit if(context.getValue(metier.getName()+param_pop.getName()+"flag") != null && (int) context.getValue(metier.getName()+param_pop.getName()+"flag")!=0){ // tac deja atteint cette annee et metier concern result = true; }else if(context.getValue("TACatteint"+param_pop.getName())==null || !(Boolean) context.getValue("TACatteint"+param_pop.getName())){ // TAC pas encore atteint jusqu ici, test step log.info( "TAC pas encore atteint jusqu ici, test"); double TAC = 0; int year = step.getYear(); if (year==0) { TAC = param_tacInTons2010; } else if (year==1) { TAC = param_tacInTons2011; } else if (year==2) { TAC = param_tacInTons2012; } else if (year==3) { TAC = param_tacInTons2013; } else if (year==4) { TAC = param_tacInTons2014; } else if (year==5) { TAC = param_tacInTons2015; } else if(param_tacInKgs != 0){ TAC = param_tacInKgs; } else if(context.getValue("TAC_" + param_pop.getName() ) != null){ TAC = (Double) context.getValue("TAC_" + param_pop.getName() ); } else TAC = 0; double landings = 0; //int year = step.getYear(); ResultStorage matResult = context.getSimulationStorage().getResultStorage(); for (TimeStep dat = new TimeStep(0); dat.before(step); dat = dat.next()) { if( dat.getYear() == year) { MatrixND mat = matResult.getMatrix(dat, param_pop, ResultName.MATRIX_DISCARDS_WEIGHT_PER_STR_MET_PER_ZONE_POP); MatrixND matc = matResult.getMatrix(dat, param_pop, ResultName.MATRIX_CATCH_WEIGHT_PER_STRATEGY_MET_PER_ZONE_MET); landings += matc.sumAll(); landings -= mat.sumAll(); } } log.info("landings = " + landings); //} log.info("[TAC] landings = " + landings+ " >= TAC:" + TAC); if (landings >= TAC) { context.setValue("TACatteint"+param_pop.getName(),true); // visible pour les metiers suivants de la boucle log.info("tac atteint"); } } // Le TAC est atteint if(context.getValue("TACatteint"+param_pop.getName())!=null && (Boolean) context.getValue("TACatteint"+param_pop.getName())){ result = true; if(param_LandingsObligation){ context.setValue("priceSwitch"+param_pop.getName(),1); if(param_DeMinimis){ // If met landed >0.05% of pop landings -> forbidden // compute landings per met and landings tot double quantMat = 0; double quantMatPop = 0; int year = step.getYear(); ResultStorage matResult = context.getSimulationStorage().getResultStorage(); SiMatrix siMatrix = SiMatrix.getSiMatrix(context); List Pops = context.getPopulationMonitor().getPopulations(); for (TimeStep dat = new TimeStep(0); dat.before(step); dat = dat.next()) { if( dat.getYear() == year) { for(Population pop:Pops){ MatrixND tmp = matResult.getMatrix(dat, pop, ResultName.MATRIX_CATCH_PER_STRATEGY_MET_PER_ZONE_POP); quantMat += tmp.getSubMatrix(1,metier,1).sumAll(); if (pop.getName().equals(param_pop.getName())){ quantMatPop += tmp.getSubMatrix(1,metier,1).sumAll(); } } } } // compute % if(quantMatPop/ quantMat > 0.05) { context.setValue(metier.getName()+param_pop.getName()+"flag",2); }else { context.setValue(metier.getName()+param_pop.getName()+"flag",1); } }else{ // strict application double quantMatPop = 0; ResultStorage matResult = context.getSimulationStorage().getResultStorage(); SiMatrix siMatrix = SiMatrix.getSiMatrix(context); List Pops = context.getPopulationMonitor().getPopulations(); for (TimeStep dat = new TimeStep(0); dat.before(step); dat = dat.next()) { for(Population pop:Pops){ if (pop.getName().equals(param_pop.getName())){ MatrixND tmp = matResult.getMatrix(dat, pop, ResultName.MATRIX_CATCH_PER_STRATEGY_MET_PER_ZONE_POP); quantMatPop += tmp.getSubMatrix(1,metier,1).sumAll(); } } } // metier catch sole ? if(quantMatPop > 0.0) { // yes -> forbidden context.setValue(metier.getName()+param_pop.getName()+"flag",2); } // else can still fish flag stays at 0 } }else { // no LO fishes but discard TargetSpecies ts = metier.getMetierSeasonInfo(step.getMonth()).getSpeciesTargetSpecies(param_pop.getSpecies()); if (ts != null && ts.getPrimaryCatch()) { // recupere tous les metiers qui ont l'espece en capture principale =>metiers vises // aimedMetiers ne fonctionne pas je ne sais pas pourquoi ! mais au final forbiddenMetier aura le meme effet context.setValue(metier.getName()+param_pop.getName()+"flag",2); log.info(metier.getName()+"flag"+2); } else { context.setValue(metier.getName()+param_pop.getName()+"flag",1); log.info(metier.getName()+"flag"+1); } } } else result = false; } 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 concerne */ @Override public void preAction(SimulationContext context, TimeStep step, Metier metier) throws Exception { if((int) context.getValue(metier.getName()+param_pop.getName()+"flag") == 2){ context.getMetierMonitor().addforbiddenMetier(metier); //recupere toutes les strategies pratiquant le metier et pour lesquelles la proportion !=0 SiMatrix siMatrix = SiMatrix.getSiMatrix(context); Set strs = new HashSet(); for (Strategy str : siMatrix.getStrategies(step)) { double prop = str.getStrategyMonthInfo(step.getMonth()) .getProportionMetier(metier); if (prop != 0) { strs.add(str); } } for (Strategy str : strs) { StrategyMonthInfo smi = str.getStrategyMonthInfo(step .getMonth()); // 1er cas de figure: l'effort est reporte sur un metier de la // meme strategie, n'ayant pas l'espece comme capture principale // et pechant avec le meme engin Set possibleMetierCase1 = new HashSet(); // second cas de figure: on cherche un metier de substitution // sans condition sur les engins, mais qui soit pratique Set possibleMetierCase2 = new HashSet(); // 3 eme cas de figure: on cherche des metiers non vises, // sans consideration sur les engins, et pour lesquels la // proportion peut etre nulle Set possibleMetierCase3 = new HashSet(); for (EffortDescription effort : str.getSetOfVessels() .getPossibleMetiers()) { Metier newMetier = effort.getPossibleMetiers(); if ( /*!aimedMetiers.contains(newMetier) &&*/!newMetier.getName().equalsIgnoreCase("nonActivity") && !newMetier.getName().equalsIgnoreCase("nonActivite") && !newMetier.getName().equalsIgnoreCase("non Activite") && !context.getMetierMonitor().getForbiddenMetier() .contains(newMetier)) { possibleMetierCase3.add(newMetier); if (smi.getProportionMetier(newMetier) != 0) { possibleMetierCase2.add(newMetier); if (metier.getGear().equals(newMetier.getGear())) { possibleMetierCase1.add(newMetier); } } } } Set possibleMetier = null; if (possibleMetierCase1.size() != 0) { log.info("[TAC] Use case 1"); possibleMetier = possibleMetierCase1; } else if (possibleMetierCase2.size() != 0) { log.info("[TAC] Use case 2"); possibleMetier = possibleMetierCase2; } else if (possibleMetierCase3.size() != 0) { log.info("[TAC] Use case 3"); possibleMetier = possibleMetierCase3; } if (possibleMetier != null) { // on repartit maintenant l'effort entre les differents metiers // possibles dans la meme strategie si un metier possible existe // bien la repartion est proportionnelle a l'effort deja alloue // dans la strategie double somme = 0; for (Metier met : possibleMetier) { somme += smi.getProportionMetier(met); } for (Metier met : possibleMetier) { double newProportion; if (somme == 0) { // cas ou aucun autre metier n'est pratique // on repartit quand meme l'effort equitablement // sur tous les autres metier newProportion = smi.getProportionMetier(metier) / possibleMetier.size(); } else { newProportion = smi.getProportionMetier(met) + (smi.getProportionMetier(metier) * smi.getProportionMetier(met) / somme); } smi.setProportionMetier(met, newProportion); log.info("[TAC] set new proportion to " + newProportion + " for " + met.getName()); } smi.setProportionMetier(metier, 0); //le metier vise a alors une proportion nulle log.info("[TAC] il y a des metiers possibles"); } else { log.info("[TAC] Use no activity"); // sinon on met tout dans le metier nonActivite MetierMonitor metierMon = context.getMetierMonitor(); MatrixND mat = metierMon.getOrCreateNoActivity(step, ResultName.MATRIX_NO_ACTIVITY, siMatrix .getStrategies(step), siMatrix .getMetiers(step)); mat.setValue(str, metier, smi.getProportionMetier(metier)); smi.getProportionMetier().setValue(metier, 0); } } } affectation = true; } /** * Si la condition est vrai alors cette action est executee 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 concerne */ @Override public void postAction(SimulationContext context, TimeStep step, Metier metier) throws Exception { // la postaction s'applique si TAC atteint et remplace tailleMin (qui ne s'applique pas si TAC atteint) // Si Landing_Obligation et TAC atteint metier interdit : donc pas de capture donc pas de rejet // Si pas Landing_Obligation : metier avec flag1 rejette tout sans ogive if (affectation) { PopulationMonitor popMon = context.getPopulationMonitor(); int groupDim = 2; int zoneDim = 3; MatrixND discard = popMon.getDiscard(step, param_pop); //if(discard == null){ discard = popMon.getCatch(param_pop).copy(); discard.setName(ResultName.MATRIX_DISCARDS_PER_STR_MET_PER_ZONE_POP); //} MatrixND eff = popMon.getN(param_pop); // on iter que sur les valeurs != 0, car si deja zero, ca ne // sert a rien de le mettre a 0 if (param_propSurvie > 0) { for (MatrixIterator i = discard.iteratorNotZero(); i.next();) { int[] pos = i.getCoordinates(); Object[] coordonnees = i.getSemanticsCoordinates(); Metier met = (Metier) coordonnees[1]; /* Normalement inutile car metier interdit captures = 0 if((int) context.getValue(met.getName()+"flag") == 2){ i.setValue(0); }else */ PopulationGroup group = (PopulationGroup) coordonnees[groupDim]; Zone zone = (Zone)coordonnees[zoneDim]; eff.setValue(group, zone, eff.getValue(group, zone) + i.getValue() * param_propSurvie); } } popMon.addDiscard(step, param_pop, discard); //log.info("fin de affecterCaptureRejetTailleMin"); // on a affecte une fois cette meta pop au rejet il ne faut pas le // refaire pour ce pas de temps affectation = false; } } }