View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.simulation;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Map.Entry;
23  
24  import org.jamesii.SimSystem;
25  import org.jamesii.core.math.random.generators.IRandom;
26  import org.jamesii.core.util.misc.Pair;
27  
28  import p3j.database.IP3MDatabase;
29  import p3j.experiment.results.ExecutionSummary;
30  import p3j.experiment.results.ResultsOfTrial;
31  import p3j.misc.errors.GeneratorError;
32  import p3j.misc.gui.GUI;
33  import p3j.misc.math.Matrix2D;
34  import p3j.pppm.IProjectionModel;
35  import p3j.pppm.SubPopulation;
36  import p3j.pppm.parameters.ParameterAssignment;
37  import p3j.pppm.parameters.ParameterInstance;
38  import p3j.pppm.parameters.ParameterType;
39  import p3j.simulation.assignments.plugintype.IParamAssignmentGenerator;
40  import p3j.simulation.calculation.deterministic.InFlowDescendantPopulation;
41  import p3j.simulation.calculation.deterministic.InFlowPopulation;
42  import p3j.simulation.calculation.deterministic.JumpOffPopulation;
43  import p3j.simulation.calculation.deterministic.parameters.BasicParameters;
44  import p3j.simulation.calculation.deterministic.parameters.InFlowDescendantParameters;
45  import p3j.simulation.calculation.deterministic.parameters.InFlowParameters;
46  import p3j.simulation.calculation.deterministic.parameters.JumpOffParameters;
47  
48  /**
49   * This class holds all data structures and methods that are required to use an
50   * {@link IParamAssignmentGenerator} for a single execution of the PPPM.
51   * 
52   * Created: August 17, 2008
53   * 
54   * @author Christina Bohk
55   * @author Roland Ewald
56   * 
57   */
58  public class SingleExecution {
59  
60    /**
61     * Auxiliary mapping of generation-independent parameters. The key is the name
62     * of the associated parameters.
63     */
64    private Map<String, ParameterAssignment> genIndepParameters;
65  
66    /**
67     * Auxiliary mapping of generation-dependent parameters. The i-th element is a
68     * map containing all parameter assignments for the i-th generation. The key
69     * is the name of the associated parameters.
70     */
71    private List<Map<String, ParameterAssignment>> genDepParameters;
72  
73    /** The projection setup, contains all input data. */
74    private final IProjectionModel projection;
75  
76    /** The list containing the populations that define a jump-off population. */
77    private final List<SubPopulation> jumpOffPopulations;
78  
79    /** The list containing the populations that define a yearly in-flow. */
80    private final List<SubPopulation> inFlowPopulations;
81  
82    /** The database to store results in. */
83    private final IP3MDatabase database;
84  
85    /** The random number generator to be used. */
86    private final IRandom random;
87  
88    /**
89     * Default constructor.
90     * 
91     * @param proj
92     *          the projection containing all input data
93     * @param dataBase
94     *          the database to store results in
95     */
96    public SingleExecution(IProjectionModel proj, IP3MDatabase dataBase) {
97      projection = proj;
98      jumpOffPopulations = projection.getSubPopulationModel()
99          .getJumpOffPopulations();
100     inFlowPopulations = projection.getSubPopulationModel()
101         .getInFlowPopulations();
102     database = dataBase;
103     random = SimSystem.getRNGGenerator().getNextRNG();
104   }
105 
106   /**
107    * Sets up and executes a single variable assignment for the PPPM.
108    * 
109    * @param generator
110    *          the assignment generator to be used
111    * @return error log from the {@link IParamAssignmentGenerator}
112    */
113   public Pair<ExecutionSummary, List<GeneratorError>> execute(
114       IParamAssignmentGenerator generator) {
115 
116     Pair<ExecutionSummary, List<GeneratorError>> result = null;
117 
118     try {
119       Pair<Map<ParameterInstance, ParameterAssignment>, List<GeneratorError>> assignment = chooseAssignment(
120           generator, random);
121 
122       // Create parameter classes
123       int years = projection.getYears();
124       ExecutionSummary executionSummary = new ExecutionSummary(projection
125           .getSubPopulationModel().getSubPopulations(),
126           assignment.getFirstValue());
127 
128       for (SubPopulation jumpOffPopulation : jumpOffPopulations) {
129         JumpOffParameters jumpOffParameters = setupBasicJumpOffParameters(
130             years, jumpOffPopulation);
131         JumpOffPopulation nativePopulation = new JumpOffPopulation();
132         executionSummary.setJumpOffParameters(jumpOffPopulation,
133             jumpOffParameters);
134         executionSummary.addResults(jumpOffPopulation, 0, nativePopulation
135             .calculatePopulation(jumpOffPopulation.getName(), 0,
136                 jumpOffParameters));
137 
138         if (jumpOffPopulation.isConsistingOfDescendantGenerations())
139           throw new UnsupportedOperationException(); // TODO
140       }
141 
142       for (SubPopulation inFlowPopulation : inFlowPopulations) {
143         calculateFirstInFlowPopulation(executionSummary, inFlowPopulation,
144             years);
145         if (inFlowPopulation.isConsistingOfDescendantGenerations())
146           for (int i = 1; i < projection.getGenerations(); i++) {
147             calculateInFlowChildPopulation(executionSummary, inFlowPopulation,
148                 i, years);
149           }
150       }
151       storeResultsToDB(executionSummary);
152       result = new Pair<ExecutionSummary, List<GeneratorError>>(
153           executionSummary, assignment.getSecondValue());
154     } catch (Throwable t) {
155       GUI.printErrorMessage("Execution failed", t);
156     }
157     return result;
158   }
159 
160   /**
161    * Stores results to database.
162    * 
163    * @param executionSummary
164    *          the execution summary
165    */
166   private void storeResultsToDB(ExecutionSummary executionSummary) {
167     ResultsOfTrial results = new ResultsOfTrial(projection, executionSummary);
168     database.saveTrialResults(results);
169   }
170 
171   /**
172    * Lets the {@link IParamAssignmentGenerator} choose a valid assignment and
173    * sets up all auxiliary data structures according to this.
174    * 
175    * @param generator
176    *          the component for generating the assignment to be calculated
177    * @param rng
178    *          the random number generator
179    * @return error log from the {@link IParamAssignmentGenerator}
180    */
181   protected Pair<Map<ParameterInstance, ParameterAssignment>, List<GeneratorError>> chooseAssignment(
182       IParamAssignmentGenerator generator, IRandom rng) {
183 
184     Pair<Map<ParameterInstance, ParameterAssignment>, List<GeneratorError>> generatorResults = generator
185         .chooseParamAssignments(rng);
186 
187     // Generate parameter assignment
188     Map<ParameterInstance, ParameterAssignment> assignments = generatorResults
189         .getFirstValue();
190 
191     // Create data structures to hold generation-dependent and
192     // generation-independent parameters
193     genIndepParameters = new HashMap<String, ParameterAssignment>();
194     genDepParameters = new ArrayList<Map<String, ParameterAssignment>>();
195     for (int i = 0; i < projection.getGenerations(); i++) {
196       genDepParameters.add(new HashMap<String, ParameterAssignment>());
197     }
198 
199     for (Entry<ParameterInstance, ParameterAssignment> assignmentEntry : assignments
200         .entrySet()) {
201       if (assignmentEntry.getKey().getParameter().isGenerationDependent()) {
202         genDepParameters.get(assignmentEntry.getKey().getGeneration()).put(
203             assignmentEntry.getKey().getParameter().getName(),
204             assignmentEntry.getValue());
205       } else {
206         genIndepParameters.put(assignmentEntry.getKey().getParameter()
207             .getName(), assignmentEntry.getValue());
208       }
209     }
210     return generatorResults;
211   }
212 
213   /**
214    * Retrieve the value for a generation-independent parameter.
215    * 
216    * @param parameterName
217    *          the parameter name
218    * @return value for the given parameter
219    */
220   protected Matrix2D getGenIndepParameter(String parameterName) {
221     ParameterAssignment parameterAssignment = genIndepParameters
222         .get(parameterName);
223     return DeviationCalculator.calculateAssignmentDeviation(
224         parameterAssignment, random);
225   }
226 
227   /**
228    * Retrieve the value for a generation-dependent parameter.
229    * 
230    * @param parameterName
231    *          the parameter name
232    * @param generation
233    *          the generation of the parameter
234    * @return value for the given parameter
235    */
236   protected Matrix2D getGenDepParameter(String parameterName, int generation) {
237     ParameterAssignment parameterAssignment = genDepParameters.get(generation)
238         .get(parameterName);
239     return DeviationCalculator.calculateAssignmentDeviation(
240         parameterAssignment, random);
241   }
242 
243   /**
244    * Calculates the first generation of emigrants.
245    * 
246    * @param executionSummary
247    *          execution summary to be filled with the results
248    * @param subPopulation
249    *          the sub-population
250    * @param years
251    *          the number of years for which shall be predicted
252    */
253   void calculateFirstInFlowPopulation(ExecutionSummary executionSummary,
254       SubPopulation subPopulation, int years) {
255     InFlowParameters parameters = new InFlowParameters(years,
256         projection.getMaximumAge());
257     parameters.setMigrantsXm(getGenIndepParameter(ParameterType.MIGRATION
258         .getMaleLabelFor(subPopulation)));
259     parameters.setMigrantsXf(getGenIndepParameter(ParameterType.MIGRATION
260         .getFemaleLabelFor(subPopulation)));
261     setupBasicInFlowPopulationParameters(parameters, subPopulation, 0);
262     InFlowPopulation migPopulation = new InFlowPopulation();
263     executionSummary.setInFlowParameters(subPopulation, parameters);
264     executionSummary.addResults(subPopulation, 0, migPopulation
265         .calculatePopulation(subPopulation.getName(), 0, parameters));
266   }
267 
268   /**
269    * Calculates a child population of the emigrants sub-population.
270    * 
271    * @param executionSummary
272    *          execution summary to be filled with the results
273    * @param subPopulation
274    *          the sub-population
275    * @param generation
276    *          the generation of the child population
277    * @param years
278    *          the number of years for which shall be predicted
279    */
280   void calculateInFlowChildPopulation(ExecutionSummary executionSummary,
281       SubPopulation subPopulation, int generation, int years) {
282     InFlowDescendantParameters parameters = new InFlowDescendantParameters(
283         years, projection.getMaximumAge());
284     parameters.setOldFertX(executionSummary.getParameters(subPopulation,
285         generation - 1).getFertX());
286     parameters.setOldMeanXf(executionSummary.getResults(subPopulation,
287         generation - 1).getMeanXf());
288     setupBasicInFlowPopulationParameters(parameters, subPopulation, generation);
289     InFlowDescendantPopulation migChildPopulation = new InFlowDescendantPopulation();
290     executionSummary.setDescendantParameters(subPopulation, generation,
291         parameters);
292     executionSummary.addResults(subPopulation, generation, migChildPopulation
293         .calculatePopulation(subPopulation.getName(), generation, parameters));
294   }
295 
296   /**
297    * Creates basic native parameters.
298    * 
299    * @param years
300    *          number of years for which shall be predicted
301    * @param jumpOffPopulation
302    * @return parameters to calculate native population prediction
303    */
304   JumpOffParameters setupBasicJumpOffParameters(int years,
305       SubPopulation jumpOffPopulation) {
306 
307     JumpOffParameters nativeParameters = new JumpOffParameters(years,
308         projection.getMaximumAge());
309 
310     nativeParameters.setPEndSYm(getGenIndepParameter(ParameterType.JUMP_OFF
311         .getMaleLabelFor(jumpOffPopulation)));
312     nativeParameters.setPEndSYf(getGenIndepParameter(ParameterType.JUMP_OFF
313         .getFemaleLabelFor(jumpOffPopulation)));
314 
315     nativeParameters.setMortXm(getGenIndepParameter(ParameterType.MORTALITY
316         .getMaleLabelFor(jumpOffPopulation)));
317     nativeParameters.setMortXf(getGenIndepParameter(ParameterType.MORTALITY
318         .getFemaleLabelFor(jumpOffPopulation)));
319 
320     nativeParameters
321         .setDeathProbInfant1halfMale(getGenIndepParameter(ParameterType.PROP_INF_DEATHS_FIRST_6M
322             .getMaleLabelFor(jumpOffPopulation)));
323     nativeParameters
324         .setDeathProbInfant1halfFemale(getGenIndepParameter(ParameterType.PROP_INF_DEATHS_FIRST_6M
325             .getFemaleLabelFor(jumpOffPopulation)));
326 
327     nativeParameters
328         .setSurviveProbO100m(getGenIndepParameter(ParameterType.SURV_PROB_OPEN_END
329             .getMaleLabelFor(jumpOffPopulation)));
330     nativeParameters
331         .setSurviveProbO100f(getGenIndepParameter(ParameterType.SURV_PROB_OPEN_END
332             .getFemaleLabelFor(jumpOffPopulation)));
333 
334     nativeParameters
335         .setMaleRateLiveBirth(getGenIndepParameter(ParameterType.PROP_MALE_LIVE_BIRTHS
336             .getLabelFor(jumpOffPopulation)));
337 
338     nativeParameters.setFertX(getGenIndepParameter(ParameterType.FERTILITY
339         .getLabelFor(jumpOffPopulation)));
340 
341     return nativeParameters;
342   }
343 
344   /**
345    * Sets up immigrant parameters.
346    * 
347    * @param parameters
348    *          basic parameters (to be filled)
349    * @param subPopulation
350    *          the sub-population
351    * @param generation
352    *          the generation for which the parameters should be set
353    */
354   void setupBasicInFlowPopulationParameters(BasicParameters parameters,
355       SubPopulation subPopulation, int generation) {
356 
357     parameters.setDeathProbInfant1halfMale(getGenDepParameter(
358         ParameterType.PROP_INF_DEATHS_FIRST_6M.getMaleLabelFor(subPopulation),
359         generation));
360     parameters
361         .setDeathProbInfant1halfFemale(getGenDepParameter(
362             ParameterType.PROP_INF_DEATHS_FIRST_6M
363                 .getFemaleLabelFor(subPopulation), generation));
364 
365     parameters.setMortXm(getGenDepParameter(
366         ParameterType.MORTALITY.getMaleLabelFor(subPopulation), generation));
367     parameters.setMortXf(getGenDepParameter(
368         ParameterType.MORTALITY.getFemaleLabelFor(subPopulation), generation));
369 
370     parameters.setSurviveProbO100m(getGenDepParameter(
371         ParameterType.SURV_PROB_OPEN_END.getMaleLabelFor(subPopulation),
372         generation));
373     parameters.setSurviveProbO100f(getGenDepParameter(
374         ParameterType.SURV_PROB_OPEN_END.getFemaleLabelFor(subPopulation),
375         generation));
376 
377     parameters.setFertX(getGenDepParameter(
378         ParameterType.FERTILITY.getLabelFor(subPopulation), generation));
379 
380     parameters.setMaleRateLiveBirth(getGenDepParameter(
381         ParameterType.PROP_MALE_LIVE_BIRTHS.getLabelFor(subPopulation),
382         generation));
383   }
384 }